Fix: Docker Permission Denied While Trying to Connect to the Docker Daemon Socket
Part of: Docker, DevOps & Infrastructure
Quick Answer
How to fix the 'permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock' error on Linux, WSL2, macOS, and CI.
The Error
You try to run a Docker command and get:
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: connect: permission deniedThe exact phrasing varies slightly depending on which Docker client subcommand you ran, but the suffix is always the same: connect: permission denied. It happens immediately, before any image is pulled or container is started, which is the clue that nothing about your Dockerfile, image, or container is at fault. The failure is at the socket layer, before Docker has even accepted your command.
Why This Happens
The Docker CLI you type commands into is a thin client. It does almost nothing on its own — it sends every command (docker ps, docker run, docker build) over a local Unix domain socket to the Docker daemon (dockerd), which is a long-running background process that actually creates containers, manages images, and configures networking.
That socket lives at /var/run/docker.sock and, on a default install, it is owned by root:docker with mode 0660. In Linux permission terms, that means only root and members of the docker group can read or write the socket. Your user account, freshly created during OS install or after running the Docker setup script, is in neither group. The kernel rejects the connect() syscall before your command ever reaches the daemon, and the CLI surfaces that rejection as the permission-denied error you see.
The daemon needs to run as root because it does things ordinary users cannot: creating network namespaces, mounting filesystems, configuring iptables/nftables rules, binding to privileged ports, and managing cgroups. Those operations require root privileges or fine-grained capabilities the kernel does not hand out to non-root processes by default. So root-ownership of the socket is not a Docker design flaw — it is the consequence of a daemon that has to be powerful enough to do its job.
The reason this confuses so many new users is that the official “get started” instructions on most Linux distributions run sudo apt install docker.io (or the Docker convenience script) and stop there. The docker group is created, the socket is configured, but your user is not added to the group automatically. You then try docker ps, get permission denied, and assume Docker is broken. It is not — you just have one more setup step.
Fix 1: Add Your User to the Docker Group
This is the right fix for personal development machines. It is also the fix the official Docker post-install instructions recommend:
sudo usermod -aG docker $USERThe -aG flags mean “append (don’t replace) to these groups.” Forgetting the a is a footgun: sudo usermod -G docker $USER removes your user from every other supplementary group (including sudo, wheel, audio, etc.), which can lock you out of sudo on the next login. Always include -a.
After running it, log out and log back in — or open a new shell that inherits the updated group membership:
newgrp dockerVerify it works:
docker psGroup membership in Linux is loaded by PAM at session start and copied into every process that the session spawns. Existing shells, tmux panes, and IDE-integrated terminals were created before the group was added, so they keep the old (empty) group set. That is why id may already show docker in your group list while groups in your current terminal does not — id re-reads from the user database while groups reflects the current process’s group set. If docker ps still fails after newgrp docker, log out fully and log back in.
Why this matters: Adding a user to the
dockergroup grants root-equivalent access to the entire host. Any user in that group can mount the host filesystem into a container and read or modify any file. On shared servers, use Fix 2 (rootless Docker) instead.
Fix 2: Use Rootless Docker (Most Secure)
Rootless Docker runs the daemon and containers entirely under your user account — no root privileges needed at all. This is the recommended approach for security-conscious setups and is the only option that genuinely separates Docker access from root access.
Install rootless Docker
dockerd-rootless-setuptool.sh installIf the setup tool is not available, install the prerequisites:
# Ubuntu/Debian
sudo apt install -y uidmap dbus-user-session
# Then run the setup
dockerd-rootless-setuptool.sh installAfter installation, add these to your ~/.bashrc or ~/.zshrc:
export PATH=/usr/bin:$PATH
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sockReload your shell and verify:
source ~/.bashrc
docker psWhy rootless is better: The standard Docker daemon runs as root, so any container escape gives an attacker root access to the host. Rootless Docker eliminates this risk entirely — a container escape lands the attacker as your user, not root. The trade-off is that some features behave differently: binding to ports below 1024 requires setcap, overlayfs needs a recent kernel, and certain network modes are restricted. For most development workflows, none of this is a blocker.
Fix 3: Use sudo (Quick but Not Recommended)
sudo docker psThis works immediately but you’ll need sudo for every Docker command, and it doesn’t fix the underlying issue. It also breaks IDE integrations, VS Code Dev Containers, and most language-specific tooling (e.g. testcontainers, Python’s docker library, npm Docker test runners) that expect to reach the daemon without prompting for a password. Use it only as a one-off check that the daemon itself is working.
Fix 4: Fix Socket Permissions (Temporary)
sudo chmod 666 /var/run/docker.sockWarning: This gives all users on the system read/write access to the Docker socket, which is equivalent to root access. This resets on reboot, but while active, any user or process on the machine can control Docker. Use Fix 1 or Fix 2 instead. For a deeper look at Linux permission errors, see Fix: bash permission denied.
Still Not Working?
Docker daemon is not running
Check if the Docker daemon is actually running. If the daemon isn’t up, you may also see connection refused errors instead of permission denied, or you might see a mix depending on socket state. For a deeper dive, see Fix: Docker daemon not running:
sudo systemctl status dockerIf it’s not running, start it:
sudo systemctl start docker
sudo systemctl enable dockerGroup membership didn’t refresh
This is the single most common reason “Fix 1 didn’t work for me.” You ran usermod -aG docker, you opened a new terminal tab, and you still get permission denied. The reason is subtle: terminal tabs spawned from an existing graphical session inherit the original session’s groups, not freshly loaded ones. To verify your current process is actually in the group:
# What the user database says
id -nG $USER
# What this exact process can see
cat /proc/self/status | grep ^GroupsIf the first command lists docker but the second doesn’t include the corresponding GID, your process inherited the stale group set. A full logout-login (not just a new tab) is the only reliable refresh on most desktop environments.
Snap-installed Docker (Ubuntu)
If you installed Docker via Snap (sudo snap install docker), the socket path and group behavior differ from the standard installation:
# Check if Docker is a snap
snap list | grep docker
# The socket may be at a different path
ls -la /var/run/docker.sockFor Snap-installed Docker, you may need to add your user to the docker group created by the snap (sometimes named snap_docker), or switch to the official Docker installation from Docker’s apt repository for better compatibility. The Snap version also sandboxes Docker in a way that breaks bind mounts to paths outside /home, which causes confusing errors that look unrelated.
Docker Desktop on Linux
Docker Desktop for Linux uses a different socket path than the standard Docker Engine:
# Docker Desktop uses this socket:
ls -la ~/.docker/desktop/docker.sockIf you have both Docker Engine and Docker Desktop installed, make sure the DOCKER_HOST environment variable points to the correct socket, or use docker context use to switch between them. Running both daemons simultaneously is supported but easy to misconfigure.
WSL2 on Windows
If you’re using Docker Desktop with WSL2 integration:
- Open Docker Desktop settings
- Go to Resources > WSL Integration
- Enable integration for your WSL2 distro
- Restart your WSL2 terminal
If the error persists in WSL2, try:
# Check if Docker socket is accessible
ls -la /var/run/docker.sockDocker Desktop should create this socket automatically when WSL integration is enabled. If /var/run/docker.sock is missing or owned by an unexpected user, restart Docker Desktop entirely — toggling WSL integration off and on usually fixes it. Note that WSL1 distros are not supported; check with wsl -l -v and upgrade with wsl --set-version <distro> 2 if needed.
macOS — no docker group exists
On macOS, there is no docker group on the host. Docker Desktop runs the daemon inside a Linux VM and exposes the socket through ~/.docker/run/docker.sock, owned by your user account. If you get permission-denied on macOS, the cause is almost always one of: Docker Desktop is not running, the symlink at /var/run/docker.sock is stale (delete and let Desktop recreate it on next start), or you have DOCKER_HOST set to a leftover value from a previous Lima/Colima install.
Inside CI/CD pipelines (GitHub Actions, GitLab CI)
Self-hosted runners often hit this error because the runner’s service user is not in the docker group. The fix is the same as Fix 1 but applied to the runner account:
sudo usermod -aG docker <runner-user>
sudo systemctl restart <runner-service>GitHub-hosted runners and GitLab.com shared runners have Docker pre-configured, so this only applies if you manage the runner yourself. For Docker-in-Docker (DinD) setups, the privileged flag and socket-mounting are separate concerns — make sure you are running the DinD service container with the right configuration before assuming this is a permission issue.
Podman compatibility mode
If you switched from Docker to Podman and pointed the docker command at Podman’s socket via DOCKER_HOST, you can hit the same error if the Podman socket service is not running:
systemctl --user start podman.socket
systemctl --user enable podman.socketPodman runs rootless by default, so the socket is in $XDG_RUNTIME_DIR/podman/podman.sock. There is no group equivalent to docker — access is governed by file ownership only.
SELinux or AppArmor blocking access
On systems with SELinux (Fedora, RHEL, CentOS, Rocky) or AppArmor (Ubuntu), security policies may block Docker socket access even when you’re in the docker group:
# Check SELinux denials
sudo ausearch -m avc -ts recent | grep docker
# Temporarily set SELinux to permissive to test
sudo setenforce 0
docker ps # if this works, SELinux was blocking it
sudo setenforce 1 # re-enableFor a permanent SELinux fix, you’ll need to create a proper policy module or ensure Docker’s SELinux integration is correctly installed via the container-selinux package. AppArmor profiles for Docker ship with the official package on Ubuntu — if you replaced or disabled them manually, reinstall apparmor-profiles and reload.
Remote Docker over SSH
If you set DOCKER_HOST=ssh://user@host, permission errors can come from the remote side: your SSH user on the remote host must be in the remote docker group, not just your local one. Verify with:
ssh user@host id -nGIf docker is not in the list on the remote side, the local fix doesn’t help — apply Fix 1 on the remote host instead.
Related: If you’re getting permission errors with npm instead of Docker, see Fix: EACCES permission denied when installing npm packages globally. For Docker Compose networking and build errors, see Fix: docker-compose networking not working and Fix: Docker daemon not running.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Docker Container Keeps Restarting
How to fix a Docker container that keeps restarting — reading exit codes, debugging CrashLoopBackOff, fixing entrypoint errors, missing env vars, out-of-memory kills, and restart policy misconfiguration.
Fix: Docker Compose Environment Variables Not Loading from .env File
How to fix Docker Compose not loading environment variables from .env files — why variables are empty or undefined inside containers, the difference between env_file and variable substitution, and how to debug env var issues.
Fix: Cannot Connect to the Docker Daemon. Is the Docker Daemon Running?
How to fix the 'Cannot connect to the Docker daemon' error on Linux, macOS, and Windows, including Docker Desktop, systemctl, WSL2, and Docker context issues.
Fix: Docker Volume Permission Denied – Cannot Write to Mounted Volume
How to fix Docker permission denied errors on mounted volumes caused by UID/GID mismatch, read-only mounts, or SELinux labels.