Most single-operator homelabs run everything as root@pam. You log in as root, every VM shows up, every setting is reachable, and that’s fine right up until you want someone else to have access too, a roommate who wants to spin up their own VM, a family member who needs to restart one container, or a script that needs to talk to the API without holding the keys to the entire cluster. At that point “just use my login” stops being a reasonable answer, and Proxmox’s actual permission system, which almost nobody touches because the default single-user setup never forces you to, becomes worth understanding.
Realms, users, and why root@pam isn’t special the way you think
Proxmox authenticates users against a “realm,” and pam is just one of several. root@pam authenticates against the host’s own Linux PAM stack, same as SSH would, which is why it’s the account that exists by default and why it can’t be deleted. For anyone else, you have two realistic choices: create more @pam accounts (real Linux users on the host, heavier-handed than you usually want) or use Proxmox’s own built-in realm, written as @pve. A @pve user is a Proxmox-only identity with no corresponding Linux account, no shell access, nothing outside the web UI and API. For giving a person or a script scoped access, @pve is almost always the right realm. Create it under Datacenter > Permissions > Users, and at creation time it starts with zero permissions anywhere. That blank slate is the point.
If your homelab already has a directory service, Proxmox also supports LDAP and Active Directory realms, which is worth knowing about but overkill for a one-or-two-person setup. Stick with @pve unless you already have a reason to need it.
Roles are the permission bundles, paths are where they apply
Proxmox splits access control into two pieces that only make sense together: a role (what actions are allowed, a bundle of individual privileges like VM.PowerMgmt or VM.Console) and a path (where in the resource tree that role applies, a specific VM, a whole node, a storage target, or the entire datacenter). A permission is the combination of a user (or group), a role, and a path, with an option to propagate down the tree.
Proxmox ships a set of built-in roles that cover the common cases without you building anything from scratch:
PVEVMAdmin- full control over a VM/container (start, stop, console, snapshot, config) but no host-level access.PVEVMUser- console and power management only, no config changes. The right fit for “let someone use the VM, not reconfigure it.”PVEAuditor- read-only everywhere it’s assigned. Useful for a dashboard account or a monitoring integration that should never be able to change anything.PVEDatastoreAdmin- manage a storage target without touching VMs at all.
You can also build a custom role from individual privileges under Datacenter > Permissions > Roles if none of the built-ins fit, though for most homelab cases the stock roles cover it.
Pools: the piece that makes per-VM access manageable
Assigning a role to one VM at a time works for a single machine, but it falls apart fast once someone has three or four VMs they’re supposed to manage. This is what pools are for: a named group of VMs/containers (and optionally storage) that you can grant a single permission against instead of repeating the grant per resource. Create a pool under Datacenter > Permissions > Pools, add the relevant guests to it, then grant the user’s role against the pool’s path instead of each VM individually. Add a new VM to that pool later and the existing permission covers it automatically, no second grant needed.
This is the practical shape of “give my roommate their own lane”: create a pool, drop their VMs into it, grant their @pve user PVEVMAdmin on that pool’s path, and they can fully manage anything inside it while having zero visibility into your VMs, your storage config, or the node itself.
A worked example: roommate access to their own VMs, nothing else
- Datacenter > Permissions > Pools - create a pool, something like
roommate-vms. - Move or create their VMs/containers inside that pool.
- Datacenter > Permissions > Users - add a new user, realm
@pve, set a password (or skip the password and issue them a token instead, covered below). - Datacenter > Permissions > Add - select the user, path
/pool/roommate-vms, rolePVEVMAdmin, leave propagate on.
That’s the whole grant. They log into the same web UI with their own credentials and see exactly one pool’s worth of VMs. They can’t see your node’s storage, your other guests, or the datacenter-level settings, because nothing was ever granted at those paths.
API tokens: the right way to let a script talk to Proxmox
The moment you’re running Terraform, a backup script, or a monitoring pull against the Proxmox API, resist the urge to embed the root password in a config file somewhere. Proxmox API tokens solve this properly: under Datacenter > Permissions > API Tokens, you create a token tied to a specific user, give it its own token ID, and critically, you can scope its permissions independently of that user’s own web-UI permissions. A token can be deliberately weaker than the user it belongs to.
The practical pattern: create a dedicated @pve user purely to own tokens (don’t reuse your own login), grant that user only the specific role and path a given automation task actually needs, then issue a token under it with “Privilege Separation” left on so the token inherits exactly that scope and nothing more. A Terraform workflow that only needs to clone VMs from a template and manage their lifecycle should get a token scoped to PVEVMAdmin on the relevant pool, not an unscoped token tied to root. If that token ever leaks, a compromised credential with VM-level reach in one pool is a contained incident. A leaked root token is the whole cluster.
Tokens are presented to you exactly once at creation time, copy the secret immediately, Proxmox doesn’t store it in a form you can retrieve again. If you lose it, revoke the token and issue a new one, don’t leave an orphaned token sitting around with no idea where the secret went.
Two-factor authentication, while you’re in here
Since you’re already in Datacenter > Permissions, it’s worth enabling TOTP two-factor for any account that has real reach, root included. It’s under each user’s settings (or Datacenter > Permissions > Two Factor for a cluster-wide default), works with any standard TOTP app, and takes under a minute to set up. A firewall and a tight RBAC setup both assume the account itself hasn’t been handed over; 2FA is what actually protects that assumption if a password leaks somewhere unrelated to Proxmox entirely.
What this isn’t a substitute for
Permissions control what an authenticated user or token can do inside Proxmox. They don’t replace the firewall rules that control what can reach the web UI or API in the first place, and they don’t replace keeping the host itself patched. A roommate with a perfectly scoped PVEVMAdmin grant on their own pool is still a real account with a real password, and the API is still reachable from wherever your firewall rules let it be reached from. Treat RBAC as the second layer, not the only one: lock down who can even get to the login page, then make sure what they can do once they’re past it matches what they actually need, not what’s convenient to grant once and forget about.