VPS Tutorials
How to Fix Docker Permission Denied on a VPS (2026): docker.sock, User Groups, and bind mount Permission Troubleshooting
When Docker on a VPS reports Got permission denied while trying to connect to the Docker daemon socket, or a container gets Permission denied after mounting a directory, the common causes include the current user not being in the docker group, the session not being refreshed, abnormal /var/run/docker.sock permissions, a different rootless Docker socket path, and a UID/GID mismatch on the bind mount. This article troubleshoots layer by layer: the host Docker socket, user groups, active sessions, mounted directories, and container users.

Docker's Permission denied is easy to misread.
The same permission error can occur in two completely different places:
- You run
docker pson the host and get a message that it cannot connect to the Docker daemon socket. - The container has already started, but accessing a mounted directory reports
Permission denied.
The former means the host user does not have permission to access the Docker socket; the latter means the UID/GID of the process inside the container does not match that of the host directory. These two kinds of problems cannot be solved with the same set of commands. Many people run chmod 777 as soon as they see a permission error; it may not error out in the short term, but over time it messes up security and data ownership.
This article troubleshoots the most common Docker permission problems on a VPS: first solve /var/run/docker.sock, then look at the docker user group and session refresh, and finally handle bind mounts, container users, rootless Docker, and socket mounts in CI/CD.
If you run:
docker ps
and see:
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
this is a permission problem with the host user accessing the Docker daemon.
If you see this in container logs or when operating the application:
Permission denied: '/data/cache'
open /app/storage/logs/app.log: permission denied
this is usually the container user failing to write to the host-mounted directory.
Distinguish these two layers first, then act.
Before looking at permissions, first confirm Docker itself is not down:
systemctl status docker
If the service is not started:
sudo systemctl enable --now docker
Then look at the socket file:
ls -l /var/run/docker.sock
Common output:
srw-rw---- 1 root docker 0 May 25 10:00 /var/run/docker.sock
The key here is: the socket belongs to root:docker, and the permissions are usually 660. That is, root and members of the docker group can access it.
If the Docker service itself is abnormal, do not rush to change permissions. You can check:
journalctl -u docker --since "30 minutes ago"
If you are not yet familiar with system logs, you can first read: How to read VPS logs: journalctl, systemctl, Nginx, application logs.
Check the groups the current user belongs to:
id
If docker is not in there, add the current user:
sudo usermod -aG docker $USER
If you are granting permission to another user:
sudo usermod -aG docker deploy
Note that -aG must not be omitted. -G docker removes the user from other supplementary groups, which may cause new permission problems.
After adding the group, do not judge it as a failure right away. The group information in the current SSH session is not refreshed automatically.
Many people run:
sudo usermod -aG docker $USER
then immediately run:
docker ps
and still get permission denied, so they think the command did not work. In fact you need to log in again, or temporarily refresh the groups:
newgrp docker
Then try again:
docker ps
The more reliable way is to exit SSH and log in again:
exit
After reconnecting, run:
id
docker ps
If id already contains docker but you still have no permission, continue to check whether the socket permissions have been broken.
Some tutorials tell you to run:
sudo chmod 777 /var/run/docker.sock
Do not do this.
Being able to access the Docker socket is basically equivalent to getting host root privileges. Because a user can start a container that mounts the host root directory and then modify host files.
For example:
docker run --rm -it -v /:/host debian:12 chroot /host bash
So joining the docker group is itself a high-privilege operation. It is more sensitive than ordinary "can run containers". In production, do not casually add business users, web users, and CI users to the docker group.
If you have messed up the socket permissions, you can first restart Docker to let it restore the defaults:
sudo systemctl restart docker
ls -l /var/run/docker.sock
If it is still abnormal, then check the systemd socket or the distribution package configuration; do not force your way through with 777.
If:
sudo docker ps
runs, but:
docker ps
does not, it means the Docker daemon is fine and the problem is the current user's permissions.
At this point, do not permanently write all Docker commands as sudo docker .... For a personal VPS this also works, but it has two side effects:
- Generated files may be owned by root.
- The permissions of subsequent Compose, CI, and deployment scripts will become more chaotic.
A better recommendation: clarify which user is responsible for deployment, add it to the docker group, and then run Docker as that user.
If you installed rootless Docker, the socket is not necessarily at:
/var/run/docker.sock
but may be at:
/run/user/1000/docker.sock
Check the environment variables:
echo $DOCKER_HOST
Common rootless Docker settings:
export DOCKER_HOST=unix:///run/user/1000/docker.sock
If you call Docker in a systemd service, cron, or CI script, the DOCKER_HOST in an interactive shell may not exist. Set it explicitly in the script, or use the correct user's environment.
This kind of problem is also often mixed up with scheduled tasks. If Docker runs manually in cron but fails when run automatically, you can refer to: What to do when VPS scheduled tasks do not run.
Another common problem is that the container starts successfully but the application fails to write files.
For example, in Compose:
services:
app:
image: my-app
volumes:
- ./data:/app/data
The application inside the container reports an error when writing to /app/data. At this point, first look at the host directory permissions:
ls -ld ./data
stat ./data
Then look at which user the container process actually runs as:
docker exec -it app id
ps aux
If the user inside the container is UID 1000, while the host directory is owned by root and has no write permission, it will fail.
You can change the directory ownership to the corresponding UID/GID:
sudo chown -R 1000:1000 ./data
Or specify the running user explicitly in Compose:
services:
app:
image: my-app
user: "1000:1000"
volumes:
- ./data:/app/data
Do not start with:
chmod -R 777 ./data
This lets any local user write, and the security boundary is too coarse.
Databases, object storage simulation directories, and web upload directories are the most easily broken by permission problems.
For example, the data directory of a MySQL container must be writable by the mysql user inside the container. If you mount a root-owned directory into it, the container may fail to start directly, or leave erroneous files after initializing halfway.
Troubleshooting order:
docker logs mysql
ls -ld ./mysql-data
docker exec -it mysql id mysql
If it is a web application, such as Laravel, WordPress, or Nextcloud, you usually need to confirm:
- The
storage/uploads/cachedirectories are writable. - Whether the UID/GID of Nginx/PHP-FPM/application containers are consistent.
- Whether the host backup script restores files as root-owned.
If you encounter Web 502/504 and there are permission errors in the logs, you can compare with: What to do when a VPS shows 502 / 504 Bad Gateway.
Many CI/CD tutorials write:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
This way the CI runner inside the container can control the host Docker. But the risk is also high: if the CI job is controlled by malicious code, the attacker can control the host Docker and further gain host privileges.
The more reliable approach depends on the scenario:
- Small personal VPS: can be used temporarily, but only for trusted projects.
- Multi-person teams: isolate the CI runner to a separate machine.
- High security requirements: use rootless Docker, remote builders, or a dedicated build environment.
Do not expose the Docker socket to public web application containers.
When you encounter Docker permission denied, check in this order:
systemctl status dockerto confirm the Docker daemon is normal.ls -l /var/run/docker.sockto see the socket owner and permissions.idto see whether the current user is in thedockergroup.sudo usermod -aG docker $USERto add the user group.- Exit SSH and log in again, or run
newgrp docker. - Do not
chmod 777 /var/run/docker.sock. - If it is rootless Docker, check
DOCKER_HOSTand/run/user/UID/docker.sock. - If writing to a bind mount fails, check the host directory owner and the UID/GID inside the container.
- Use
chown UID:GIDor Composeuser:to align permissions. - In CI/CD scenarios, mount
/var/run/docker.sockwith caution.
Docker's Permission denied must first be layered: is it the host user being denied access to the Docker socket, or the process inside the container being denied writing to a mounted directory?
The former is usually solved with the docker user group and logging in again; the latter requires aligning the UID/GID of the host directory and the container user. What you really should not do is a blanket chmod 777, especially /var/run/docker.sock. Docker socket permissions are essentially close to root privileges; whoever you give access to is whoever you trust to control this VPS.