Fix Permission Denied in itzg/minecraft-server with UID/GID and Bind Mounts

Seeing permission errors in /data or files that Docker cannot write? This guide explains why itzg/minecraft-server defaults to UID 1000:GID 1000 and how to fix ownership safely.

Docker Operations
setupmc.com Team

Need a cleaner baseline?

Generate a Compose setup before you keep patching by hand

If you are still refining the server baseline, use the configurator to create a cleaner Docker Compose setup and then return to the guides for the next issue.

Open configurator

Recognizing the problem

This guide is for the classic Docker bind-mount failure:

  • the container starts, but cannot write under /data
  • plugins, configs, or world files fail to update
  • logs mention Permission denied

With itzg/minecraft-server, this usually comes down to one mismatch:

the host filesystem ownership does not match the user that runs the Minecraft process inside the container.

Why this happens

By default, the image switches to UID 1000 and GID 1000. If your bind-mounted host directory belongs to a different user or group, writes can fail.

That is common when:

  • the directory was created by root
  • the server was migrated from another host
  • the host user has a different UID than 1000

Quick fix

If you intentionally want to keep the default container user, fix the ownership on the host:

sudo chown -R 1000:1000 ./data

Then recreate or restart the stack:

docker compose up -d

Option 1: Keep the default container user and fix the host

This is the simplest setup and the one I recommend for most single-server deployments.

Compose:

services:
  mc:
    image: itzg/minecraft-server:latest
    volumes:
      - ./data:/data

Host fix:

sudo chown -R 1000:1000 ./data
find ./data -maxdepth 2 -ls | head

This keeps the image on its documented default.

Option 2: Match the container user to your host user

If your host directory should stay owned by a different user, set UID and GID explicitly:

services:
  mc:
    image: itzg/minecraft-server:latest
    environment:
      UID: "1001"
      GID: "1001"
    volumes:
      - ./data:/data

This is useful when you already standardized file ownership on the host and want the container to follow it.

Option 3: Use Compose user only when you mean it

Docker also supports a Compose-level user: setting:

services:
  mc:
    user: "1001:1001"

That works, but it changes the container-level user behavior more broadly. If your goal is simply to align with the image's supported ownership model, UID and GID are usually clearer.

How to validate the fix

After restarting the stack:

docker compose logs -f

You want to see normal startup without repeated permission failures. Then test a write path, for example:

  • change server.properties
  • add a plugin
  • trigger save-all through RCON

If the server can write under /data, the fix is complete.

Common anti-patterns

chmod -R 777

This is the usual panic move and almost never the right long-term answer. It weakens the host filesystem permissions and makes future ownership debugging harder.

Mixing ownership models casually

Do not switch randomly between:

  • default 1000:1000
  • custom UID/GID
  • Compose user

Pick one model and keep it consistent.

Forgetting SELinux or rootless specifics

If you use Podman or an SELinux/AppArmor-heavy setup, the bind mount may need extra labeling such as :Z. That is a different class of failure than plain UID/GID mismatch.

Troubleshooting

SymptomLikely causeFix
Permission denied on /dataHost ownership mismatchAlign ownership with container UID/GID
Files were created as rootEarlier commands used sudo or root containerCorrect ownership recursively
Config still will not changeContainer recreated with old mount or old envRe-run docker compose up -d and inspect the effective config
Admin commands work, file writes failRCON path is fine, filesystem is notFocus on bind mount ownership, not networking

FAQ

Which option should I choose?

For most setups: keep the default 1000:1000 and make the host directory match it.

Do named volumes avoid some of these issues?

Yes. Bind mounts expose host ownership problems more directly. Named volumes can be simpler when you do not need direct host-side editing.

Next steps

Frequently asked questions

Short answers to the questions that usually come up while working through this topic.