Skip to main content
Docker permission guide

Docker PUID, PGID, and UMASK Permissions Explained

When a Docker bind mount returns permission denied, start with host identity and new-file defaults. Most failures come from three layers: which host user the process writes as, which host group owns the shared folder, and which mode the process gives new files and directories.

Quick answer

On a system Docker daemon running as root without user namespace remapping, PUID should match the host user ID the container process should write as, and PGID should match the host group ID the container process should write as. Rootless Docker and userns-remap translate those container IDs, so matching the visible numbers is not enough in those modes. UMASK controls default permissions for newly created files and directories when the image supports it.

If files arrive as 644 and another service cannot edit them, the creating process probably used a mask like 022. Use the Umask Calculator to compare 022, 002, 027, and 077 before changing a container environment.

What this guide covers

This guide explains how Docker container IDs map to Linux file permissions. For Syncthing, Samba, FileBrowser, and Docker shared-folder checks, use the Syncthing Shared Folder Permissions guide.

For existing mode bits, the Chmod Calculator helps check explicit modes such as 644, 755, 775, 2775, and 777.

Runs locally

Docker PUID/PGID permission diagnostic

Compare a bind-mounted directory with the identity and umask configured for a container. The result separates an existing directory access problem from a future file-creation problem.

These variables are image-specific, not Docker defaults.
Choose how the container should receive write access.
From stat -c "%u" /srv/shared.
From stat -c "%g" /srv/shared.
Use three or four octal digits.
The host UID the application should use.
The host GID used for shared writes.
For example, 022 or 002.

Checking the example configuration

This checks numeric IDs, Unix mode bits, setgid, and expected umask output. ACLs, SELinux labels, rootless mappings, and network filesystems can still change the effective result.

Docker bind mount permission denied decision table

Match the failure to the layer that controls it before changing ownership or widening the mode.

Symptom Check Likely layer Next action
The app starts but cannot create a file stat -c "%u:%g %a %n" /srv/shared Host UID, GID, or directory write/execute bits Match PUID/PGID to the intended owner or group, then verify the directory mode.
Files still arrive as root after setting PUID/PGID Read the image parameter documentation The image ignores unsupported environment variables Use the image's documented user setting or a compatible Compose user configuration.
One container writes, but a second container cannot edit stat -c "%u:%g %a %n" new-file New files are commonly landing as 644 Use a shared PGID and compare UMASK=022 with UMASK=002.
The container fails before the app starts Inspect the full host path and mount definition Missing source path, parent-directory traversal, or SELinux label Fix the host path or label; changing PUID/PGID cannot repair a mount the daemon cannot access.
UID, GID, and mode match, but access is still denied getfacl /srv/shared and inspect Docker mode ACL, SELinux, rootless/user namespace, NFS, or CIFS Check the controlling layer instead of applying chmod 777.
PUID/PGID look correct, but the host shows a high-numbered UID/GID or the host user loses access docker exec container_name cat /proc/self/uid_map Rootless Docker or userns-remap translated the container identity Trace the active UID/GID map and subordinate ranges before using chown.
chmod 777 works temporarily Compare owner, group, and the effective permission class The failure is permission-related, but the owner, group, or creation defaults still do not match Restore a narrower mode and fix identity, group inheritance, umask, or ACL rules.

What PUID means

PUID is a convention used by many Docker images to choose the user ID that the application should run as inside the container. On a system Docker daemon running as root without user namespace remapping, the useful value is usually the numeric UID of the host user that should own new bind-mounted files.

Check it with id or id username on the host. If the host folder is owned by UID 1000 but the container writes as UID 10000, one service may create files that another service cannot edit.

What PGID means

PGID is the group ID the container process should write as. For shared folders, this often matters more than the username because several services can safely cooperate through one trusted group.

If Syncthing, a media service, FileBrowser, and a Samba process all need access, make sure the bind-mounted folder uses a group all writers can join. Group ownership must match the mode bits; a shared group cannot write a file that was created as 644.

What UMASK means

UMASK is a creation mask. It removes permission bits from the usual defaults for new files and directories. Common Linux file creation starts from 666, and directory creation starts from 777.

umask 022 usually creates files 644 and directories 755. That is readable by group and others, but not group-writable. UMASK=002 is commonly used for trusted shared groups because it often creates files as 664 and directories as 775.

Why files become 644 instead of group-writable

A new regular file usually starts from 666. With UMASK=022, the group write bit is removed, so the result is 644. The group can read the file, but cannot modify it.

This is why a bind-mounted folder can look correct at first: the directory may be accessible, the group owner may be right, and read access may work. The write failure appears only when another process tries to modify a file created by the first process.

Complete Docker Compose example: shared Syncthing folder

This example uses the documented LinuxServer Syncthing image, which supports PUID, PGID, and an optional UMASK. It assumes a system Docker daemon running as root without userns-remap. The host user is UID 1000, the shared group is GID 1001, and the shared directory uses setgid mode 2775.

1. Confirm the inputs and prepare the host paths

id media
# uid=1000(media) gid=1000(media) groups=1000(media),1001(shared-data)

getent group shared-data
# shared-data:x:1001:media

sudo install -d -o 1000 -g 1000 -m 0750 /srv/syncthing/config
sudo install -d -o 1000 -g 1001 -m 2775 /srv/shared
stat -c "%u:%g %a %n" /srv/shared
# 1000:1001 2775 /srv/shared

2. Use those numeric IDs in Compose

services:
  syncthing:
    image: lscr.io/linuxserver/syncthing:latest
    container_name: syncthing
    environment:
      PUID: "1000"
      PGID: "1001"
      UMASK: "002"
      TZ: "Etc/UTC"
    volumes:
      - type: bind
        source: /srv/syncthing/config
        target: /config
      - type: bind
        source: /srv/shared
        target: /data1
    ports:
      - "8384:8384"
      - "22000:22000/tcp"
      - "22000:22000/udp"
      - "21027:21027/udp"
    restart: unless-stopped

3. Validate the configuration and inspect real output

docker compose config
docker compose up -d
docker top syncthing -eo pid,user,group,args

# After Syncthing creates or receives a file:
stat -c "%u:%g %a %n" /srv/shared/path/to/new-file
# Typical result: 1000:1001 664 /srv/shared/path/to/new-file

The application can request a stricter mode, so the host-side stat result is the final check. Changing UMASK does not rewrite existing 644 files; use chmod or an ownership correction separately when old content is already wrong.

Configured identityPUID=1000
PGID=1001
Expected new file1000:1001
664 with umask 002
Expected new directory1000:1001
775 with setgid inheritance

PUID and PGID are not built into Docker

PUID, PGID, and UMASK only work when the image reads those variables. LinuxServer images document that convention; an arbitrary image may ignore all three values and continue running as the user declared by its Dockerfile.

For an image without PUID/PGID support, check whether its documentation allows Compose user: "1000:1001". Some images need their normal startup user to initialize files or drop privileges, so do not force user without confirming compatibility.

When matching IDs still look wrong

Rootless Docker and userns-remap translate container IDs through subordinate UID/GID ranges. A file can therefore appear as one numeric owner inside the container and another on the host.

Use the rootless and user namespace checks below before changing ownership. On SELinux hosts, a correct Unix mode can still be blocked by the label. On NFS or CIFS mounts, server-side identity mapping and mount options can override local ownership changes.

Read-only checks

Rootless Docker and userns-remap: trace the real host ID

A high-numbered host owner such as 232071 is not automatically a bad chmod or a broken image. Rootless Docker and userns-remap can translate a container UID into a different host UID. Read the active map first; changing permissions cannot correct an identity mapping you have not identified.

1. Confirm which Docker daemon you are using

docker context show
docker info --format '{{json .SecurityOptions}}'
grep -n '"userns-remap"' /etc/docker/daemon.json 2>/dev/null

A rootless daemon reports rootless in its security options. A system daemon using userns-remap commonly reports name=userns; its daemon configuration identifies the remap user. Checking the context matters when the same host has both a system daemon and a rootless daemon.

2. Compare the identities and active namespace maps

id
stat -c "%u:%g %a %n" /srv/shared

docker exec container_name id
docker exec container_name stat -c "%u:%g %a %n" /data1
docker exec container_name cat /proc/self/uid_map
docker exec container_name cat /proc/self/gid_map

Each map row contains the starting ID inside the container, the corresponding starting ID on the host, and the length of that range. Treat /proc/self/uid_map and /proc/self/gid_map as the active mapping; /etc/subuid and /etc/subgid show the ranges assigned on the host.

3. Interpret the common one-range mappings

Docker mode Container UID 0 appears on the host as Container UID n appears on the host as
System Docker daemon running as root, without userns-remap UID 0 UID n
userns-remap, subordinate range starts at S S S + n
Rootless Docker, daemon user is H, subordinate range starts at S Host UID H S + (n - 1) for n >= 1

For example, if the rootless daemon user is host UID 1000 and its subordinate range starts at 231072, container UID 0 maps to host UID 1000, while container UID 1000 maps to host UID 232071. In that setup, setting PUID=1000 does not make the process write as host UID 1000.

4. Check the assigned subordinate ranges

id -un
awk -F: -v name="$(id -un)" -v uid="$(id -u)" '$1 == name || $1 == uid' /etc/subuid
awk -F: -v name="$(id -un)" -v uid="$(id -u)" '$1 == name || $1 == uid' /etc/subgid

# For userns-remap, replace REMAP_USER with the daemon's configured remap user:
grep "^REMAP_USER:" /etc/subuid
grep "^REMAP_USER:" /etc/subgid

For userns-remap, check the daemon's userns-remap setting to identify the remap user. Docker commonly creates dockremap when the setting is default, but the configured name can be different.

5. Stop before recursive ownership changes

  • Do not run chown -R until you know which host identity the container actually uses. A recursive change can lock the host user or another service out of the same directory.
  • Podman's :U mount option is not a Docker bind-mount option. Podman documents that it recursively changes the source volume owner and group, so do not copy that fix into a Docker setup without understanding the host-side change.
  • On NFS and CIFS mounts, the file server and mount options can decide the effective identity. A local ownership change may fail or may not change what the server authorizes.
  • After any intentional fix, create a test file from inside the container and inspect its numeric owner on the host. That verifies the application path and the mapped process identity together.

Shared folder example

A practical shared folder setup usually combines a shared host group, group-owned directory, setgid inheritance, and a cooperative umask. Setgid helps new files inherit the directory group, while UMASK=002 helps new files keep group write permission.

sudo groupadd shared-data
sudo usermod -aG shared-data username
sudo chgrp -R shared-data /srv/shared
sudo chmod 2775 /srv/shared
sudo setfacl -d -m g:shared-data:rwx /srv/shared

Default ACLs are useful when one or more containers cannot be configured to create group-writable files reliably. ACLs give the shared folder an inherited rule that survives more application-specific defaults.

Common mistakes

  • Setting PUID and PGID from the container user instead of the host user and group that own the bind-mounted path.
  • Using UMASK=022 in a folder where a trusted group needs write access to new files.
  • Adding setgid but forgetting that setgid alone does not force group-write when the process creates files as 644.
  • Using chmod 777 as a permanent fix. If 777 works, it is a temporary diagnostic signal that the failure is permission-related, not a safe long-term configuration.

When to use chmod, umask, setgid, or ACL

chmod changes permissions on existing files. umask controls default permissions for new files and directories. Setgid controls group inheritance on directories. Default ACLs help when future files need inherited group permissions but a service does not honor the desired umask.

Need Start with Why
Existing files have the wrong mode Chmod Calculator Use chmod when the files or directories already exist.
Future files are created as 644 Umask Calculator Use umask when the problem is a default creation mode.
You are choosing between chmod and umask Linux Permission Diagnosis Separate existing mode fixes from future default fixes.
New files need shared group ownership setgid directory Setgid makes new children inherit the directory group.
Containers ignore the desired umask default ACL ACL inheritance can keep shared folders writable by the group.

Docker shared-folder troubleshooting order

Use this order when a bind-mounted folder works in one container but fails in another. Verify each layer on the host before changing broad permissions.

Step Command or setting What it tells you
1. Confirm the host identity id username and docker exec container_name id Compares the intended host writer with the process identity inside the container.
2. Inspect the bind mount stat -c "%U %G %a %n" /srv/shared Shows whether the owner, group, and current mode match the intended writer.
3. Test new-file defaults docker exec container_name sh -c 'touch /data1/permission-test' Tests the container's actual process identity and mounted path instead of the host shell user.
4. Check inheritance stat -c "%u:%g %a %n" /srv/shared/permission-test and getfacl /srv/shared Shows the new file's numeric owner and mode, plus any inherited ACL rules.
5. Then adjust the model PGID, UMASK=002, setgid, or default ACL Choose the narrow fix instead of making the entire mount world-writable.

Verification commands

Verify permissions from both the host and the container. The host-side result is what matters for a bind-mounted path.

docker info --format '{{json .SecurityOptions}}'
id
id username
stat -c "%U %G %a %n" /srv/shared
docker exec container_name id
docker exec container_name cat /proc/self/uid_map
docker exec container_name cat /proc/self/gid_map
docker exec container_name sh -c 'touch /data1/permission-test'
stat -c "%u:%g %a %n" /srv/shared/permission-test
getfacl /srv/shared

For a quick decision path, use the Chmod vs Umask guide. To browse the full category, return to the Linux Permission Tools hub.

Related WebUtilsLab permission pages

Use these pages together when a Docker shared folder mixes host identity, group ownership, default modes, and existing file permissions.

Official references and supported environments

Last verified July 20, 2026. This guide targets Linux hosts and containers that write to bind-mounted paths. PUID, PGID, and UMASK are image-specific environment variables, not universal Docker settings; confirm the variables supported by the image you run.

Docker PUID, PGID, and UMASK permissions FAQ

How do I fix Docker bind mount permission denied?

Check the host folder owner and group, match PUID to the host writer UID, match PGID to the shared host group, then verify new-file modes with stat. Use UMASK=002, setgid, or default ACLs when trusted services need shared group writes.

What should PUID be in Docker?

PUID should map to the host user ID that the container process should write as. Use id or id username on the host to confirm the numeric value.

What should PGID be in Docker?

PGID should map to the host group ID that should own or write shared files. For shared folders, multiple services usually need one trusted group.

Why does UMASK=022 create files as 644?

Common file creation starts from 666. UMASK=022 removes group-write and other-write, so new files often become 644 and directories become 755.

Is UMASK=002 safer than chmod 777?

For trusted shared groups, yes. UMASK=002 usually keeps write access inside owner and group permissions, while chmod 777 grants write access to everyone.

Does setgid force group write?

No. Setgid makes new files and directories inherit the directory group, but it does not force group-write if the creating process uses a mask that removes group write.

When should I use default ACLs?

Use default ACLs when future files need inherited group permissions and one or more containers cannot be configured to create group-writable files reliably.

Why does Docker create files with a high-numbered UID on the host?

Rootless Docker and userns-remap translate container IDs to host IDs. Read /proc/self/uid_map and /proc/self/gid_map inside the container, then compare the active ranges with /etc/subuid and /etc/subgid before changing ownership.

Are PUID and PGID built into Docker?

No. They are image-specific environment-variable conventions. Confirm that the image supports them; otherwise use the image's documented user configuration or a compatible Docker Compose user setting.