How to fix chown: changing ownership of '/data': Operation not permitted in Docker

DockerINTERMEDIATEMEDIUMUpdated Dec 6, 2025· 594 views

This error occurs when a Docker container attempts to change file ownership using chown, but the operation is blocked due to volume mount restrictions, filesystem limitations, user namespace remapping, or insufficient permissions. Common fixes include mounting to parent directories, using COPY --chown in Dockerfiles, or adjusting host permissions before container startup.

Quick fix

Fixes chown: changing ownership of '/data': Operation not permitted

# docker-compose.yml - WRONG approach
services:
  mongodb:
    image: mongo:latest
    volumes:
      - ./data:/data/db  # Container can't chown /data/db

# docker-compose.yml - CORRECT approach
services:
  mongodb:
    image: mongo:latest
    volumes:
      - ./data:/data  # Mount to parent, container creates /data/db itself
  1. Mount to parent directory instead of target path
  2. Use named volumes instead of bind mounts
  3. Set host directory permissions before starting container
  4. Use COPY --chown in Dockerfile for build-time files
docker — error
# docker-compose.yml - WRONG approach
services:
mongodb:
image: mongo:latest
volumes:
- ./data:/data/db # Container can't chown /data/db
# docker-compose.yml - CORRECT approach
services:
mongodb:
image: mongo:latest
volumes:
- ./data:/data # Mount to parent, container creates /data/db itself
chown: changing ownership of '/data': Operation not permitted

What this error means

The "chown: changing ownership of '/path': Operation not permitted" error in Docker indicates that a process inside your container tried to change the owner or group of a file or directory, but the operation was denied by the system. This error is particularly common with: 1. **Bind-mounted volumes**: When you mount a host directory into a container, the container may not have permission to change ownership of files that reside on the host filesystem. 2. **Database containers**: Official images for MongoDB, MySQL, PostgreSQL, and other databases often run entrypoint scripts that attempt to chown data directories for the correct service user. 3. **User namespace remapping**: When Docker uses user namespaces, the UID/GID inside the container are mapped to different values on the host, causing ownership operations to fail. 4. **Filesystem limitations**: Some filesystems (like exFAT, NTFS, or certain network shares) do not support Unix-style ownership and permissions. The error typically appears during container startup when entrypoint scripts try to ensure proper file ownership, or when applications attempt to create and own their data directories.

Typical symptoms

  • Container fails to start with 'chown: changing ownership' error
  • Database containers (MongoDB, MySQL, PostgreSQL) crash on startup
  • Error appears in container logs mentioning '/var/lib/mysql', '/data/db', or similar paths
  • Permission errors only occur with bind mounts, not with named volumes
  • Container works on Linux but fails on Docker Desktop (Windows/macOS)
  • Error occurs after enabling Docker user namespace remapping
  • COPY --chown in Dockerfile has no effect and files remain owned by root

Common causes

  1. Bind-mounted volume prevents container from changing ownership on host filesystem
  2. Filesystem does not support Unix permissions (exFAT, NTFS, network shares)
  3. User namespace remapping causes UID/GID mismatch between container and host
  4. NFS mount with root_squash enabled blocks root ownership changes
  5. Container runs as non-root user without CAP_CHOWN capability
  6. SELinux or AppArmor policies blocking ownership changes
  7. macOS or Windows filesystem restrictions through Docker Desktop
  8. Cloud platform (OpenShift, Kubernetes) enforcing non-root security policies

How to fix "chown: changing ownership of '/data': Operation not permitted"

1Mount to parent directory instead of target path

For database containers like MongoDB, the most common fix is to mount your volume to the parent directory instead of the exact data path:

yaml
# docker-compose.yml - WRONG approach
services:
  mongodb:
    image: mongo:latest
    volumes:
      - ./data:/data/db  # Container can't chown /data/db

# docker-compose.yml - CORRECT approach
services:
  mongodb:
    image: mongo:latest
    volumes:
      - ./data:/data  # Mount to parent, container creates /data/db itself

This works because the container's entrypoint script creates the /data/db subdirectory itself and can set ownership on directories it creates.

For MySQL/MariaDB:

yaml
services:
  mysql:
    image: mysql:8
    volumes:
      - ./mysql-data:/var/lib  # Instead of /var/lib/mysql

Note: This approach may require more disk space on the host and changes how data is organized.

2Use named volumes instead of bind mounts

Named volumes are managed by Docker and have proper permission handling:

yaml
# docker-compose.yml
services:
  mongodb:
    image: mongo:latest
    volumes:
      - mongodb_data:/data/db  # Named volume works correctly

volumes:
  mongodb_data:  # Docker manages this volume

Or with docker run:

bash
# Create a named volume
docker volume create mongodb_data

# Use the named volume
docker run -v mongodb_data:/data/db mongo:latest

Named volumes:
- Are stored in Docker's volume directory (/var/lib/docker/volumes/)
- Have proper permissions set by Docker
- Can be initialized with correct ownership during first container start
- Work consistently across all platforms (Linux, macOS, Windows)

To migrate data from a bind mount to a named volume:

bash
# Create volume and copy data
docker volume create mongodb_data
docker run --rm -v ./data:/source -v mongodb_data:/dest alpine cp -a /source/. /dest/
3Set host directory permissions before starting container

Ensure the host directory has the correct ownership before the container starts:

bash
# Find the UID/GID the container expects
# For MongoDB: 999:999 (mongodb user)
# For MySQL: 999:999 (mysql user)
# For PostgreSQL: 999:999 (postgres user)

# Set ownership on host directory
sudo chown -R 999:999 ./data

# Or make it writable by anyone (less secure, for development only)
chmod -R 777 ./data

For containers that run as a specific user, check the Dockerfile or documentation for the expected UID:

bash
# Inspect the image to find the user
docker inspect mongo:latest --format '{{.Config.User}}'

# Or run a command inside to check
docker run --rm mongo:latest id

In Docker Compose, you can also specify the user:

yaml
services:
  myapp:
    image: myimage
    user: "1000:1000"
    volumes:
      - ./data:/app/data

Then set host permissions to match:

bash
sudo chown -R 1000:1000 ./data
4Use COPY --chown in Dockerfile for build-time files

When building images, use the --chown flag with COPY or ADD to set ownership during the build:

dockerfile
# Create user first
FROM node:18-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

# Copy with correct ownership
COPY --chown=appuser:appgroup ./src /app/src
COPY --chown=appuser:appgroup package*.json /app/

WORKDIR /app
RUN npm install

USER appuser
CMD ["node", "src/index.js"]

Important: The user must exist in the image before using --chown. If the user doesn't exist, the COPY command will silently use root:root.

For numeric UID/GID (works even without creating the user):

dockerfile
FROM alpine
COPY --chown=1000:1000 ./files /app/files

Note: COPY --chown only affects files copied during build. It does not help with mounted volumes at runtime.

5Handle user namespace remapping

When Docker uses user namespace remapping, UIDs inside the container map to different UIDs on the host:

bash
# Check if user namespace remapping is enabled
cat /etc/docker/daemon.json | grep userns-remap

# Check the subuid/subgid mappings
cat /etc/subuid
cat /etc/subgid
# Output example: dockremap:100000:65536

With remapping enabled, root (UID 0) inside the container becomes UID 100000 on the host. To fix permission issues:

bash
# Set host directory ownership to the remapped UID range
sudo chown -R 100000:100000 ./data

Alternatively, run the container without user namespace remapping for this specific container:

bash
docker run --userns=host -v ./data:/data myimage

Or in Docker Compose:

yaml
services:
  myapp:
    image: myimage
    userns_mode: "host"
    volumes:
      - ./data:/data

Security note: Disabling user namespace remapping reduces container isolation. Only do this when necessary.

6Fix NFS volume permissions

NFS exports typically use root_squash which maps the root user to nobody, preventing ownership changes:

Option 1: Match container user to NFS share owner

bash
# Check NFS share ownership
ls -ln /nfs/share

# Run container as that user
docker run --user 1000:1000 -v /nfs/share:/data myimage

Option 2: Configure NFS server (if you have access)

bash
# Edit /etc/exports on the NFS server
/shared/data  *(rw,sync,no_root_squash)  # Allows root operations

# Or use specific anonymous mapping
/shared/data  *(rw,sync,anonuid=999,anongid=999)

# Apply changes
sudo exportfs -ra

Option 3: Use an init container to set permissions

yaml
services:
  init-permissions:
    image: alpine
    user: root
    volumes:
      - nfs_data:/data
    command: chown -R 999:999 /data

  myapp:
    image: myimage
    depends_on:
      - init-permissions
    volumes:
      - nfs_data:/data

volumes:
  nfs_data:
    driver: local
    driver_opts:
      type: nfs
      o: addr=nfs-server,rw
      device: ":/shared/data"
7Use alternative images designed for non-root execution

Some official images require root privileges. Consider using alternative images designed for rootless environments:

Bitnami images are designed to run as non-root by default:

yaml
services:
  mongodb:
    image: bitnami/mongodb:latest
    volumes:
      - ./data:/bitnami/mongodb
    environment:
      - MONGODB_ROOT_PASSWORD=secret

  mysql:
    image: bitnami/mysql:latest
    volumes:
      - ./mysql-data:/bitnami/mysql/data
    environment:
      - MYSQL_ROOT_PASSWORD=secret

  postgresql:
    image: bitnami/postgresql:latest
    volumes:
      - ./pg-data:/bitnami/postgresql
    environment:
      - POSTGRESQL_PASSWORD=secret

Bitnami images:
- Run as non-root user (UID 1001) by default
- Don't require chown on startup
- Work better in restricted environments (OpenShift, rootless Docker)
- Have consistent permission handling across platforms

For other applications, look for images with -rootless or -unprivileged variants.

8Handle SELinux restrictions

On SELinux-enabled systems (RHEL, CentOS, Fedora), add the appropriate label to volumes:

bash
# For private volumes (single container access)
docker run -v ./data:/data:Z myimage

# For shared volumes (multiple containers)
docker run -v ./data:/data:z myimage

In Docker Compose:

yaml
services:
  myapp:
    image: myimage
    volumes:
      - ./data:/data:Z

To check if SELinux is the issue:

bash
# Check SELinux status
getenforce

# Check for SELinux denials
sudo ausearch -m avc -ts recent

# Temporarily disable for testing (don't do in production)
sudo setenforce 0

To permanently fix SELinux context:

bash
# Set the correct context on the directory
sudo semanage fcontext -a -t svirt_sandbox_file_t "./data(/.*)?"
sudo restorecon -Rv ./data

Advanced notes

Understanding the chown operation flow in containers:

When a database container starts, the entrypoint script typically:
1. Checks if the data directory exists
2. Creates it if missing
3. Runs chown to ensure the database user owns the directory
4. Starts the database process as that user

The chown fails when the container can't modify ownership of a mounted path.

Dockerfile pattern for handling permissions:

dockerfile
FROM alpine

# Create app user
RUN addgroup -S app && adduser -S app -G app

# Create data directory owned by app user
RUN mkdir -p /data && chown app:app /data

# Set as volume (ownership persists in named volumes)
VOLUME /data

USER app
CMD ["myapp"]

Entrypoint script pattern for flexible permissions:

bash
#!/bin/sh
# entrypoint.sh - Run as root, then drop privileges

# Fix permissions if running as root
if [ "$(id -u)" = "0" ]; then
    chown -R appuser:appgroup /data 2>/dev/null || true
    exec gosu appuser "$@"
fi

exec "$@"

Docker Desktop (macOS/Windows) specifics:
Docker Desktop uses a VM with file sharing. The gRPC-FUSE or VirtioFS file sharing backends handle permissions differently:
- Files appear owned by the user running Docker Desktop
- chown operations may silently succeed but have no effect
- Named volumes work correctly because they exist inside the VM

Rootless Docker considerations:
In rootless Docker, the daemon runs as a non-root user, adding another layer of UID mapping:

bash
# Host UID -> Rootless Docker UID -> Container UID
# 1000    -> 0 (root in daemon) -> 0 (root in container)

Files created by containers in rootless mode are owned by the user running the Docker daemon, not root.

Kubernetes/OpenShift considerations:
These platforms often enforce:
- runAsNonRoot: true - Containers must run as non-root
- readOnlyRootFilesystem: true - No writes to container filesystem
- Security Context Constraints (SCCs) limiting capabilities

Use init containers to fix volume permissions:

yaml
initContainers:
  - name: fix-permissions
    image: busybox
    command: ["sh", "-c", "chown -R 999:999 /data"]
    volumeMounts:
      - name: data
        mountPath: /data
    securityContext:
      runAsUser: 0

Frequently asked questions

What does "chown: changing ownership of '/data': Operation not permitted" mean?
The "chown: changing ownership of '/path': Operation not permitted" error in Docker indicates that a process inside your container tried to change the owner or group of a file or directory, but the operation was denied by the system. This error is particularly common with: 1. Bind-mounted volumes: When you mount a host directory into a container, the container may not have permission to change ownership of files that reside on the host filesystem.
How do I fix "chown: changing ownership of '/data': Operation not permitted"?
This error occurs when a Docker container attempts to change file ownership using chown, but the operation is blocked due to volume mount restrictions, filesystem limitations, user namespace remapping, or insufficient permissions. Common fixes include mounting to parent directories, using COPY --chown in Dockerfiles, or adjusting host permissions before container startup.
What causes "chown: changing ownership of '/data': Operation not permitted"?
Bind-mounted volume prevents container from changing ownership on host filesystem Filesystem does not support Unix permissions (exFAT, NTFS, network shares) User namespace remapping causes UID/GID mismatch between container and host
Is the "chown: changing ownership of '/data': Operation not permitted" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading