# Docker: permission denied connecting to the daemon socket

The Docker CLI is a client for a daemon that owns a root-owned Unix socket. The error is a filesystem permission on that socket, not a Docker configuration problem — and the most common cause is a group that was granted but never applied to the running session.

> Confidence: high · Verified: 2026-08-10 · Status: fresh · Source: https://knowbase.sh/k/docker-permission-denied-daemon-socket

## Error signature

```
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
```

Codes: EACCES

## Problem

Every docker command fails with permission denied, while the same command under sudo works. Nothing is wrong with Docker itself: the CLI is talking to a daemon over a Unix socket owned by root, and the calling user cannot open that file. The usual first fix — adding the user to the docker group — appears to do nothing, because a process cannot gain a group it did not have when it started.

## Root cause

- **The user is not a member of the docker group** _(primary)_
  - The daemon creates the socket owned by root and group-owned by docker. A user outside that group has no access at all, so every command fails identically and immediately.
  - How to tell: id -nG lists no docker group, and ls -l /var/run/docker.sock shows group docker
- **The group was granted but the current session predates it** _(primary)_
  - usermod changes the account, not the processes already running under it. A shell, a desktop session or an SSH connection started before the change keeps its original group set until it is replaced.
  - How to tell: id -nG in the current shell omits docker while id -nG $USER, which reads the account rather than the process, includes it
- **The daemon is running rootless and the client is pointed at the system socket** _(common)_
  - Rootless mode puts the socket under the user's own runtime directory. The CLI still defaults to /var/run/docker.sock, which either does not exist or belongs to a separate root daemon the user has no access to.
  - How to tell: /run/user/$(id -u)/docker.sock exists, DOCKER_HOST is unset, and dockerd is running as the user rather than as root
- **Inside a container, the mounted socket's group does not exist in the container** _(common)_
  - Bind-mounting the host socket carries its numeric owner and group, not their names. The container's user is rarely in a group with that GID, so the socket is unreadable even when the same user can use Docker on the host.
  - How to tell: stat -c '%g' /var/run/docker.sock inside the container returns a GID that id -G in that container does not list
- **The socket's ownership or mode was changed** _(edge)_
  - A hardened image, a configuration management run, or a manual chmod can leave the socket owned by something other than root:docker. Group membership is then correct and still insufficient.
  - How to tell: ls -l /var/run/docker.sock shows an owner or group other than root docker, or a mode without group read and write

## Solution

1. Separate a permission problem from an absent daemon before changing anything. If the socket does not exist, this is not the failure you are reading about.

```bash
ls -l /var/run/docker.sock && systemctl is-active docker
```

   Note: A missing socket or an inactive daemon produces "Cannot connect to the Docker daemon ... Is the docker daemon running?", which no amount of group membership will fix.
2. Compare the groups of the running shell against the groups of the account. A difference between the two is the whole diagnosis for the most common case.

```bash
id -nG; id -nG "$USER"
```

3. Add the user to the docker group if the account itself lacks it.

```bash
sudo usermod -aG docker "$USER"
```

   Note: This grants root-equivalent access to the host. Where that is unacceptable, rootless mode is the supported alternative rather than loosening the socket.
4. Replace the session so the new group is applied. Logging out and back in is the reliable form; newgrp changes only the shell that runs it.

```bash
newgrp docker   # or log out and back in
```

5. If the daemon is rootless, point the client at the user's own socket instead of the system one.

```bash
export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock
```

   Note: Put this in the shell profile; a rootless daemon started by systemd --user will otherwise be invisible to every new shell.
6. Inside a container that mounts the host socket, give the container process the socket's numeric group rather than changing the socket.

```bash
# read the GID from the host socket and grant it to the container
docker run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  --group-add "$(stat -c '%g' /var/run/docker.sock)" \
  my-image
```

   Note: chmod 666 on the socket also silences the error and hands every process on the host root-equivalent control of Docker. Prefer the GID.

**Verify:** docker version prints both a Client and a Server section without sudo, in a newly opened shell rather than the one that was patched.

**If that fails:** Where the group cannot be granted — a locked-down host, or a build agent you do not control — run the daemon in rootless mode under the user's own account, which needs no privileged group at all.

## Applies to

- Docker Engine: all versions on Linux — The socket path and group are defaults; both are configurable in daemon.json.
- Runtimes: dockerd, rootless dockerd
- Platforms: linux, ci runners, wsl2

## Not applicable to

- Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running? — the daemon is stopped rather than unreadable
- Docker Desktop on macOS or Windows, where the client reaches a VM and host group membership does not apply
- Permission denied raised by a process inside a container against its own filesystem, which is unrelated to the daemon socket
- Registry authentication failures such as pull access denied, which occur after the daemon has been reached

## Evidence

1. [Docker — Linux post-installation steps for Docker Engine](https://docs.docker.com/engine/install/linux-postinstall/) — Docker Inc. (official-docs), read 2026-08-10
   Supports: That the daemon communicates over a root-owned Unix socket rather than a port, that access is granted through the docker group, that a session must be restarted before new membership takes effect, and — on the same page — that the group is a root-equivalent privilege grant.
   > The Docker daemon binds to a Unix socket, not a TCP port. By default it's the `root` user that owns the Unix socket, and other users can only access it using `sudo`.
2. [Docker — Rootless mode](https://docs.docker.com/engine/security/rootless/) — Docker Inc. (official-docs), read 2026-08-10
   Supports: That the daemon can run entirely as a non-root user, which relocates the socket out of /var/run and makes the system socket the wrong target for the client.
   > Rootless mode lets you run the Docker daemon and containers as a non-root user to mitigate potential vulnerabilities in the daemon and the container runtime.
3. [Docker CLI reference — environment variables](https://docs.docker.com/reference/cli/docker/) — Docker Inc. (official-docs), read 2026-08-10
   Supports: That DOCKER_HOST is what selects which daemon socket the client connects to, making it the fix when a rootless daemon listens somewhere other than the default.
   > Daemon socket to connect to.

## Confidence

high — The socket ownership model, the docker group as the access mechanism, the need to re-establish a session, the existence of a rootless socket elsewhere and the role of DOCKER_HOST are each quoted from Docker's own documentation. The container-GID case is an inference from documented bind-mount behaviour rather than a sentence about this error, and the changed-permissions case is diagnostic rather than documented.

## If this is not your failure

Look yours up instead of adapting this one: https://knowbase.sh/search.json?q=<your error text>

To narrow the causes above to the one you have, run the discriminator on each and POST
`{"slug":"docker-permission-denied-daemon-socket","observations":"<what they returned>"}` to https://knowbase.sh/diagnose.json.
It answers with the cause your observations identify and why the others are excluded.

The same three calls as MCP tools: https://knowbase.sh/mcp

---

Retrieved from https://knowbase.sh/k/docker-permission-denied-daemon-socket · knowbase · CC-BY-4.0
