# Fix "Permission Denied" Connecting to the Docker Daemon

URL: https://www.devopsness.com/blog/fix-docker-permission-denied
Author: Kiril Urbonas
Published: 2026-07-08
Updated: 2026-10-03
Categories: DevOps
Tags: Docker, Linux, Containers, DevOps, Debugging

Summary: The daemon socket is owned by root, and your user isn't allowed to touch it. Here's the fix, and why the obvious one is a security smell.

---
# Fix "Permission Denied" Connecting to the Docker Daemon

Fix "permission denied while trying to connect to the Docker daemon socket" by adding your user to the `docker` group with `sudo usermod -aG docker $USER`, then running `newgrp docker` or logging back in. The socket is readable only by root and that group. On shared machines, use rootless Docker instead, because the group is root-equivalent.

This is what it looks like on a fresh box:

```
$ docker ps
Got 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
```

Nothing is broken. Docker is running fine. Your user account just isn't allowed to talk to it.

## What's actually happening

The Docker CLI is a thin client. It doesn't do much on its own; it sends API calls over a Unix socket to the `dockerd` daemon, which does the real work of pulling images and starting containers. That socket lives at `/var/run/docker.sock`, and the daemon runs as root.

Look at who owns the socket:

```
$ ls -l /var/run/docker.sock
srw-rw---- 1 root docker 0 Jul  6 09:14 /var/run/docker.sock
```

Read that carefully. The owner is `root`, the group is `docker`, and the permission bits are `srw-rw----`. That means: root can read/write, members of the `docker` group can read/write, and everyone else gets nothing. You are "everyone else." Hence permission denied.

Confirm you're not in the group:

```
$ groups
kiril adm sudo users
```

No `docker` in that list. That's the whole problem.

## The standard fix

These are the three commands from Docker's post-install docs (the `groupadd` just reports the group already exists on most installs):

```
$ sudo groupadd docker
$ sudo usermod -aG docker $USER
$ newgrp docker
```

The `-aG` matters. `-a` appends; leave it off and `usermod` will *replace* your entire group membership with just `docker`, quietly kicking you out of `sudo`, `adm`, and everything else. People have locked themselves out of a box this way.

Group membership is read at login, so the change won't apply to shells you already have open. `newgrp docker` starts a new shell with the group; every other terminal needs a logout and login (for SSH, drop the connection and reconnect). Then verify:

```
$ id
uid=1000(kiril) gid=1000(kiril) groups=1000(kiril),4(adm),27(sudo),100(users),998(docker)
```

There it is, `998(docker)`. Now `docker ps` works without sudo.

## "But sudo docker works fine"

It does, and that's the trap. Running `sudo docker ps` sidesteps the socket permission check because root can read any socket. Plenty of people stop here, alias `docker` to `sudo docker`, and move on.

Two reasons that bites you. Files the CLI creates, like `~/.docker/config.json`, end up owned by root, and you'll be `chown`-ing them back. And it papers over the real permission model, so the next person on the box has no idea how access is granted.

Sudo working is a signal that your user account isn't wired up, not a solution.

## The part nobody mentions: docker group is root

Here's the uncomfortable truth about the "standard fix." Adding yourself to the `docker` group is, for practical purposes, granting yourself passwordless root on the machine.

The daemon runs as root, and anyone who can send it API calls can ask it to do root things. One line proves it:

```
$ docker run -v /:/host -it alpine chroot /host sh
```

That mounts the host's entire filesystem into a container and drops you into a shell with full write access to it. No password prompt. From there you can edit `/etc/shadow`, add a sudoer, read anyone's SSH keys. Docker's post-install docs say it outright: "The `docker` group grants root-level privileges to the user."

On your own laptop, fine. On a shared build server, handing out docker-group membership like read access is how you get a privilege-escalation finding in the next audit.

## What we'd reach for instead: rootless Docker

Rootless mode runs the entire daemon as your unprivileged user, using user namespaces so that "root" inside a container maps to your normal UID outside it. A container breakout gets your permissions, not the host's.

It needs `newuidmap` and `newgidmap` (the `uidmap` package) plus ranges in `/etc/subuid` and `/etc/subgid`. Then setup is one command:

```
$ dockerd-rootless-setuptool.sh install
```

That sets up a per-user daemon under systemd. Point the CLI at your own socket:

```
$ export DOCKER_HOST=unix:///run/user/1000/docker.sock
$ systemctl --user start docker
$ docker run hello-world
```

Now the socket lives under your own `/run/user/$UID`, owned by you, and no group edit is needed. The tradeoffs are real: binding ports below 1024 needs an extra capability, some storage drivers behave differently, and a few network setups need `slirp4netns` tuning. For most build and dev workloads none of that matters, and you've removed a root-equivalent group from the machine. That's a trade worth making.

If rootless doesn't fit, the next-best move is scoped access, not blanket group membership: hand specific service accounts the socket through a controlled path, or front the daemon with something that enforces policy, rather than making every developer effectively root.

## The other places this shows up

**Docker Desktop** (Mac and Windows) doesn't use a raw root socket the way native Linux does; it runs the engine inside its own VM and already isolates it from your host user. If you hit permission denied there, it's usually the Desktop app not being started, or a stale `DOCKER_HOST` pointing at a socket that no longer exists. Unset it and let Desktop manage the context:

```
$ unset DOCKER_HOST
$ docker context use desktop-linux
```

**CI runners.** In a pipeline there's no interactive login, so `newgrp` and "log back in" don't apply. The runner's service user has to be in the docker group at the time the agent process starts, or you mount the socket into the job explicitly. If you added the group but the running agent predates the change, restart the agent; it's still holding its old group set.

**systemd services.** Same shape. A unit runs as its `User=`, and group membership is resolved when the service starts, so `sudo systemctl restart your-service` after changing the group.

For a wider map of daemon and connection failures, the [Docker troubleshooting](/blog/docker-error-troubleshooting-guide) guide covers the neighboring errors this one tends to travel with.

## Questions people ask

### Why does newgrp docker fix permission denied?

Linux reads your group list when a session starts, so `usermod -aG docker $USER` changes nothing for shells already open. `newgrp docker` launches a fresh shell with the `docker` group active, which lets it open `/var/run/docker.sock`. It only fixes that one shell. Other terminals, IDEs, and SSH sessions still need a full logout and login before `docker ps` works without sudo.

### I added myself to the docker group and still get permission denied. What now?

Check four things. Run `id` and confirm `docker` appears; if not, the session predates the change. Run `ls -l /var/run/docker.sock` and confirm the group is `docker` with `rw` bits. Run `echo $DOCKER_HOST` and unset it if it points at a dead socket. If the error mentions `~/.docker/config.json`, an earlier `sudo docker` left root-owned files: `sudo chown "$USER":"$USER" ~/.docker -R`.

### Is adding a user to the docker group safe?

Only where that user could have root anyway. Docker's documentation states the group "grants root-level privileges to the user", because anyone who can reach the daemon can mount `/` into a container and edit it. On a personal workstation that is acceptable. On shared servers and CI hosts, use rootless mode, where the daemon runs as your own UID.

## The call we'd make

On your personal machine, add yourself to the docker group and get on with your day; the blast radius is you. On anything shared, build infrastructure, or anywhere an auditor will eventually look, don't. Stand up rootless Docker so a compromised container can't become a compromised host, or hand out scoped socket access to the specific accounts that need it. The docker group is a convenience that quietly means root, and treating it as anything less is a bet you don't want to be holding when it goes wrong.

## Sources

- [Docker Docs: Linux post-installation steps (manage Docker as a non-root user)](https://docs.docker.com/engine/install/linux-postinstall/)
- [Docker Docs: Rootless mode](https://docs.docker.com/engine/security/rootless/)
- [Docker Docs: Troubleshoot the Docker daemon](https://docs.docker.com/engine/daemon/troubleshoot/)

