You type docker ps and get permission denied while trying to connect to the docker API at unix:///var/run/docker.sock. With sudo the same command works. Or the error shows up inside a container that has the socket mounted, and adding the user to the docker group changes nothing.

This guide reproduces each version of the error on Ubuntu 24.04 with Docker Engine 29.9.3 and fixes it. Every command and output below comes from that lab run on November 5, 2026, with a normal user named alice.

You're not alone with this one. On Stack Overflow, How to fix Docker: Permission denied had 1,945,544 views on November 5, 2026, and Got permission denied while trying to connect to the Docker daemon socket had 962,590.

The short version:

  • Your user can't open /var/run/docker.sock, which is owned by root:docker with mode 660. Run sudo usermod -aG docker $USER, then log out and back in, or run newgrp docker. A shell that was open before usermod keeps failing.
  • If usermod says the group does not exist, run sudo groupadd docker, add the user, and restart the Docker daemon so it sets the group on the socket.
  • Inside a container, add the host's numeric group ID: --group-add "$(stat -c %g /var/run/docker.sock)", or group_add in Compose. The group name docker in the image usually has a different number.
  • Don't chmod 666 the socket. The docker group is root-equivalent, so only add trusted users, and put a socket proxy in front of apps that only read container state.

Why Docker says permission denied on docker.sock

The docker command is only a client. It talks to the Docker daemon, dockerd, through a Unix socket at /var/run/docker.sock. The daemon runs as root. Whoever can open that socket can tell it to do anything.

Terminal on Ubuntu 24.04 with Docker 29.9.3. The id command shows alice only in group 1001(alice), docker ps fails with permission denied while trying to connect to the docker API at unix:///var/run/docker.sock, and ls -l shows the socket as srw-rw---- root docker. The older Docker CLI 26.1.5 long form of the error is shown below.

What the socket permissions mean

On a fresh install, the socket looks like this:

srw-rw---- 1 root docker 0 Nov 5 02:17 /var/run/docker.sock 

Only root and members of the docker group can read and write it. In the lab, alice had groups=1001(alice), so the kernel refused the connection before Docker saw the request. sudo docker ps works because root owns the socket.

The two forms of the error

Docker CLI 29.9.3 prints a short message:

permission denied while trying to connect to the docker API at unix:///var/run/docker.sock 

Older clients print the full API call. Docker CLI 26.1.5 on Debian 13 showed:

permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.45/containers/json": dial unix /var/run/docker.sock: connect: permission denied 

Both mean the same thing, and docker compose fails the same way, because it uses the same socket.

Fix it on the host with the docker group

The fix in the Docker post-install guide is to add your user to the docker group:

sudo usermod -aG docker $USER 

That alone doesn't fix the shell you're typing in. This is the step most people miss.

Start a new session or run newgrp

Linux reads your groups when you log in. A shell that started before usermod keeps the old list. In the lab, alice had a shell open, root ran usermod -aG docker alice, and the old shell still failed:

[old shell] $ id uid=1001(alice) gid=1001(alice) groups=1001(alice) [old shell] $ docker ps permission denied while trying to connect to the docker API at unix:///var/run/docker.sock 

newgrp docker started a subshell with the new group, and a fresh login (su - alice, the same as a new SSH session) had it too. Both could run docker ps.

Terminal showing that after usermod -aG docker alice the already open shell still lists only group 1001(alice) and docker ps is denied. After newgrp docker, id shows gid=996(docker) and docker ps prints the container table. A fresh login shows groups=1001(alice),996(docker) and docker ps works.

newgrp only changes that one subshell. For every terminal and your desktop session, log out fully and log back in. The Docker guide adds that a virtual machine may need a restart. Check with id that docker is in the list before you try again. Ubuntu created the group with GID 996 here. The number differs from machine to machine.

usermod: group 'docker' does not exist

If the docker group is missing, the daemon has no group to give the socket. The lab removed the group and restarted the daemon to reproduce it. dockerd logged a warning and the socket fell back to root:root:

level=warning msg="could not change group /var/run/docker.sock to docker: group docker not found" srw-rw---- 1 root root 0 Nov 5 02:18 /var/run/docker.sock 

usermod then failed with usermod: group 'docker' does not exist and exit code 6. Create the group first:

sudo groupadd docker sudo usermod -aG docker $USER sudo systemctl restart docker 

The restart matters. Right after groupadd the socket still belonged to root:root, and docker ps as alice was still denied. Once the daemon came back up it set the socket to root:docker, and docker ps worked.

Why chmod 666 and sudo everywhere are the wrong fix

Many answers suggest sudo chmod 666 /var/run/docker.sock. It does make the error go away, because every user on the machine can now open the socket.

chmod 666 hands root to every account

That is the problem. Any process on the host, including a compromised web app running as www-data, can now start a privileged container. The change doesn't even last. In the lab the socket showed srw-rw-rw- after chmod 666, and after a daemon restart it was back to srw-rw---- root docker. You end up with an insecure fix that disappears at the next daemon restart, so the error comes back.

The docker group is root too

Adding a user to the docker group is the supported fix, but it gives the same power in a controlled way. The Docker guide is blunt about it: "The docker group grants root-level privileges to the user." The Docker security docs explain why. A container can mount the host's / directory and change the host filesystem without any restriction.

So treat docker group membership like sudo access. Add the accounts you'd trust with root, and nobody else. If you want Docker without root on the host at all, look at rootless mode, where each user runs their own daemon.

Fix permission denied inside a container

The error often appears in containers that mount the socket: CI agents, Jenkins, Portainer, Traefik, dashboards. As long as the container runs as root it works. Once the image switches to a normal user, it fails.

The group name inside the image doesn't match

The kernel checks numeric IDs, not names. In the lab, the socket on the host belonged to GID 1002. A container running as user 1000 saw this:

$ docker run --rm --user 1000:1000 -v /var/run/docker.sock:/var/run/docker.sock docker:29.9.3-cli sh -c 'ls -ln /var/run/docker.sock && getent group docker' srw-rw---- 1 0 1002 0 Nov 5 02:18 /var/run/docker.sock docker:x:2375: 

The docker:29.9.3-cli image has its own docker group with GID 2375. So --group-add docker adds group 2375, which doesn't own the socket, and docker ps still fails. That explains the Stack Overflow question where group permissions seem correct (347,311 views). Pass the host's number instead:

docker run --rm --user 1000:1000 \ --group-add "$(stat -c %g /var/run/docker.sock)" \ -v /var/run/docker.sock:/var/run/docker.sock \ docker:29.9.3-cli sh -c 'id && docker ps' 

This printed uid=1000 gid=1000 groups=1000,1002 and the container list.

Terminal on the host. stat shows the socket is root:docker with GID 1002. docker:29.9.3-cli running as user 1000 is denied. Inside the image the socket shows group 1002 while the image's docker group is 2375, so --group-add docker is still denied. With --group-add set to the stat output, id shows groups=1000,1002 and docker ps prints the container list.

Set group_add in Docker Compose

In Compose, the same fix is group_add. Read the number from an environment variable, so the file works on hosts with different GIDs:

services: ci-agent: image: docker:29.9.3-cli user: "1000:1000" group_add: - "${DOCKER_GID:?set DOCKER_GID to the GID of /var/run/docker.sock}" volumes: - /var/run/docker.sock:/var/run/docker.sock command: sleep infinity 

Then write the value into .env next to the file:

echo "DOCKER_GID=$(stat -c %g /var/run/docker.sock)" > .env docker compose up -d 

Without .env, Compose stopped right away with required variable DOCKER_GID is missing a value, which beats a container that starts and then fails. With it, id inside ci-agent showed groups=1000,1002 and docker ps listed the containers.

Diagram of who can open /var/run/docker.sock, owned by root with group docker 1002 and mode 0660. Allowed: alice after a new login with group 1002, and a container user 1000 with --group-add 1002. Denied: alice's old shell with only group 1001, and a container with --group-add docker, which resolves to GID 2375 inside the image.

Give containers less than the full socket

A container with the socket has root on your host, so group_add doesn't make it safer. It only lets a non-root process use that power. Mounting the socket with :ro doesn't limit the API either. Many apps, like Homepage or Uptime Kuma, only need to list containers. A socket proxy covers that case. Its README puts the risk plainly: "Giving access to your Docker socket could mean giving root access to your host, or even to your whole swarm".

Run docker-socket-proxy with read-only access

This Compose file puts tecnativa/docker-socket-proxy:v0.5.0 on an internal network. The app container runs as user 1000, has no socket mount and no group tricks, and talks to the proxy over TCP:

services: socket-proxy: image: tecnativa/docker-socket-proxy:v0.5.0 environment: CONTAINERS: 1 POST: 0 volumes: - /var/run/docker.sock:/var/run/docker.sock:ro networks: - socket client: image: docker:29.9.3-cli user: "1000:1000" environment: DOCKER_HOST: tcp://socket-proxy:2375 command: sleep infinity networks: - socket networks: socket: internal: true 

CONTAINERS: 1 allows the container endpoints, and POST: 0 allows only GET and HEAD requests. Don't publish port 2375 to the host.

What a 403 from the proxy means

From the client, docker ps listed both containers. Everything else was refused:

$ docker compose exec client docker run --rm docker:29.9.3-cli true docker: Error response from daemon: <html><body><h1>403 Forbidden</h1> Request forbidden by administrative rules. </body></html> 

docker images failed the same way, because IMAGES was not enabled, and so did docker stop, because it's a POST. The proxy log shows each blocked call, such as "POST /v1.56/containers/create HTTP/1.1" with status 403. When an app behind the proxy fails with this error, find the API section in its log and enable only that variable.

Terminal with docker-socket-proxy v0.5.0 set to CONTAINERS=1 and POST=0. docker ps from the client container lists the proxy and client containers. docker run returns Error response from daemon 403 Forbidden, Request forbidden by administrative rules. The proxy log shows 403 for GET images/json, POST containers/create and POST containers stop.

Errors that look like permission denied but aren't

Two other messages show up in the same searches. They need different fixes.

failed to connect to the docker API, is the daemon running

With the daemon stopped, Docker 29.9.3 printed one long line. It starts with failed to connect to the docker API at unix:///var/run/docker.sock and ends like this:

check if the path is correct and if the daemon is running: dial unix /var/run/docker.sock: connect: no such file or directory 

Older clients say Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?, a question with 3.3 million views. The key part is no such file or directory. The socket isn't there, so start the daemon with sudo systemctl start docker and check sudo systemctl status docker if it won't stay up.

A leftover DOCKER_HOST gives the same error with a different path. In the lab, DOCKER_HOST=unix:///run/user/1001/docker.sock, a rootless socket that didn't exist, made docker ps fail even though the system daemon was running. docker context ls warned that the variable overrides the active context. unset DOCKER_HOST fixed it.

WARNING: Error loading config file

If you ran sudo docker login or other sudo docker commands before, ~/.docker may belong to root. In the lab, docker ps as alice still worked but printed:

WARNING: Error loading config file: open /home/alice/.docker/config.json: permission denied 

Docker ignores your config, including registry logins, until you take the folder back:

sudo chown -R "$USER":"$USER" "$HOME/.docker" 

The warning was gone on the next run. For more permission errors, the Grafana and Prometheus volume guide covers bind mount ownership, which is a different problem from the socket.

FAQ

Running Docker without sudo

How do I run Docker commands without sudo?

Add your user to the docker group with sudo usermod -aG docker $USER, then log out and back in or run newgrp docker. Check with id that docker appears in your groups. If you'd rather not give your account root-equivalent access, use rootless mode instead.

Why does docker work with sudo but not without it?

The socket is owned by root:docker with mode 660. Root can always open it, so sudo docker works. Your user can only open it as a member of the docker group in the current session.

I added my user to the docker group. Why do I still get permission denied?

Your current shell still has the old group list. Open a new login session or run newgrp docker. If id shows the group and it still fails, check ls -l /var/run/docker.sock. A socket owned by root:root means the daemon started before the group existed, so restart it.

Security and containers

Is chmod 666 on docker.sock safe?

No. It lets every account and service on the host control Docker, which means root on the host. It also resets when the daemon restarts, so it doesn't even fix the problem for long.

Is adding a user to the docker group a security risk?

Yes, in the same way as giving that user sudo. The Docker docs state that the group grants root-level privileges. Only add trusted users, or use rootless mode.

How do I fix docker.sock permission denied in a container?

Run the container with the socket's numeric group: --group-add "$(stat -c %g /var/run/docker.sock)", or group_add in Compose. A group name like docker resolves inside the image and usually has the wrong number. If the app only reads container state, give it a socket proxy instead of the socket.