Proxmox Permission Denied Errors: Fixing API 403, ACL, Token, and Storage Issues
Resolve Proxmox VE permission denied errors including API 403 forbidden, incorrect ACL paths, token privilege separation, pool permissions, storage content types, and LXC UID mapping.
Understanding Proxmox Permissions
Proxmox VE has a powerful but complex permission system based on users, groups, roles, ACLs (Access Control Lists), and API tokens. When you encounter "403 Forbidden" or "Permission denied" errors, the cause is almost always a missing or misconfigured permission somewhere in this chain. This guide helps you pinpoint exactly where the permission gap is and how to fix it.
API 403 Forbidden Errors
The most common permission error when using the Proxmox API or web interface with non-root accounts.
# Test API access from the command line
curl -k -s https://localhost:8006/api2/json/nodes \
-H "Authorization: PVEAPIToken=user@pam!mytoken=UUID-HERE"
# If you get: {"errors":{},"data":null} or 403 Forbidden
# The token/user lacks permission for the requested resource
# Check what permissions the user has
pveum user list
pveum acl list
# Check the specific user's roles
pveum user info myuser@pam
# Common fix: assign a role at the correct path
pveum aclmod / -user myuser@pam -role PVEAuditor
# For full admin access (be careful):
pveum aclmod / -user myuser@pam -role Administrator
ACL Path Mistakes
ACLs in Proxmox are path-based, and using the wrong path is one of the most frequent permission mistakes. Permissions on /vms/100 do not grant access to the node itself or to storage.
# ACL paths in Proxmox follow this hierarchy:
# / - Root (everything)
# /nodes - All nodes
# /nodes/pve1 - Specific node
# /vms - All VMs and containers
# /vms/100 - Specific VM/container
# /storage - All storage
# /storage/local - Specific storage
# /pool - All pools
# /pool/production - Specific pool
# Common mistake: granting VM access but forgetting storage
# User can see VM 100 but cannot start it (no storage permission)
pveum aclmod /vms/100 -user myuser@pam -role PVEVMUser
# Fix: also grant storage access
pveum aclmod /storage/local-lvm -user myuser@pam -role PVEDatastoreUser
# Or use a pool to manage permissions together
pveum pool add production
pveum pool set production --vms 100,101,102 --storage local-lvm
pveum aclmod /pool/production -user myuser@pam -role PVEVMAdmin
# List current ACLs to see what is configured
pveum acl list
API Token Privilege Separation
API tokens in Proxmox have a "Privilege Separation" setting that is enabled by default. When enabled, the token has its own permissions separate from the user. When disabled, the token inherits the user's permissions.
# Create a token WITHOUT privilege separation
# (token inherits all user permissions)
pveum user token add myuser@pam mytoken --privsep 0
# Create a token WITH privilege separation (default)
# (token needs its own ACL entries)
pveum user token add myuser@pam mytoken --privsep 1
# If using privilege separation, grant permissions to the token
pveum aclmod / -token 'myuser@pam!mytoken' -role PVEVMAdmin
# Check token permissions
pveum user token list myuser@pam
# Common issue: user has correct permissions but the API
# token with privsep=1 has no permissions of its own
# Solution: either set privsep=0 or add ACLs for the token
# Verify token authentication works
curl -k https://localhost:8006/api2/json/version \
-H "Authorization: PVEAPIToken=myuser@pam!mytoken=TOKEN-VALUE"
If you manage Proxmox through automation tools or use ProxmoxR to connect to your nodes via API, getting token permissions right is essential. Start with privilege separation disabled for simplicity, then enable it once your ACL paths are working correctly.
Pool Permission Issues
Pools group VMs, containers, and storage together for easier permission management. But pool permissions only work if resources are actually assigned to the pool.
# Create a pool
pveum pool add development
# Add resources to the pool
pveum pool set development --vms 200,201,202
pveum pool set development --storage local-lvm
# Grant a user access to the pool
pveum aclmod /pool/development -user dev@pam -role PVEVMAdmin
# Common issue: VM is not in the pool
# Check pool membership
pveum pool list development
# Add a missing VM to the pool
pveum pool set development --vms 200,201,202,203
# Gotcha: adding storage to a pool only grants permission
# to use that storage, not to see all content on it
# The user can create disks on the storage but cannot
# browse other users' content
Storage Content Type Restrictions
Each storage in Proxmox has allowed content types. Even with correct permissions, you cannot perform operations that the storage does not allow.
# Check storage content type configuration
pvesm status
pvesm list local
# View allowed content types for a storage
grep -A 10 "local:" /etc/pve/storage.cfg
# Example: storage only allows images and rootdir
# content images,rootdir
# Trying to store ISOs or backups will fail
# Fix: add missing content types
pvesm set local --content images,rootdir,iso,backup,vztmpl,snippets
# Content types:
# images - VM disk images
# rootdir - Container root directories
# iso - ISO images
# backup - Backup files (vzdump)
# vztmpl - Container templates
# snippets - Snippet files (cloud-init, hookscripts)
# After changing content types, verify
pvesm status
LXC Mount UID Mapping Issues
Unprivileged LXC containers use UID/GID mapping, which means the UIDs inside the container do not match the UIDs on the host. This causes permission denied errors when accessing bind-mounted host directories.
# Default UID mapping for unprivileged containers:
# Container UID 0 (root) -> Host UID 100000
# Container UID 1000 -> Host UID 101000
# Check the container's UID mapping
pct config 200 | grep -E "unprivileged|idmap"
# Fix bind mount permissions for unprivileged containers
# Set host directory ownership to match mapped UIDs
chown -R 100000:100000 /mnt/shared-data
# For more granular control, use subuid/subgid mapping
# In /etc/pve/lxc/200.conf:
# lxc.idmap: u 0 100000 65536
# lxc.idmap: g 0 100000 65536
# To map a specific host UID into the container:
# Allow user 1000 on host to be UID 0 in container
# In /etc/pve/lxc/200.conf:
# lxc.idmap: u 0 1000 1
# lxc.idmap: u 1 100001 65535
# lxc.idmap: g 0 1000 1
# lxc.idmap: g 1 100001 65535
# Also update /etc/subuid and /etc/subgid on the host
echo "root:1000:1" >> /etc/subuid
echo "root:1000:1" >> /etc/subgid
# Restart the container for changes to take effect
pct stop 200
pct start 200
Debugging Permission Issues Systematically
When you cannot figure out which permission is missing, use these techniques to narrow it down.
# Check effective permissions for a user at a path
pveum user permissions myuser@pam --path /vms/100
# List all roles and their privileges
pveum role list
pveum role info PVEVMAdmin
# Check auth log for denied operations
journalctl -u pvedaemon | grep -i "permission\|denied\|403" | tail -20
# Test with root to confirm the operation works
# If it works as root but not as your user, it is definitely permissions
# Incrementally add permissions until it works:
# 1. Try PVEAuditor (read-only) at /
# 2. Try PVEVMUser at the specific VM path
# 3. Add PVEDatastoreUser at the storage path
# 4. Escalate to PVEVMAdmin if needed
Permission Troubleshooting Checklist
- Verify the user or token exists and can authenticate
- Check ACL paths match exactly (including the leading slash)
- For API tokens with privilege separation, verify the token has its own ACLs
- Ensure the role assigned contains the required privileges
- Check that storage content types allow the operation
- For pools, verify the resource is actually a member of the pool
- For LXC bind mounts, verify host directory ownership matches UID mapping
Permission errors in Proxmox are methodical to solve once you understand the path-based ACL system. Check the user, the path, the role, and the token privilege separation setting, and you will find the gap every time.
Take Proxmox management mobile
All the features discussed in this guide — accessible from your phone with ProxmoxR. Real-time monitoring, power control, firewall management, and more.