Skip to content
DevOps2026-09-086 min read

Cannot connect to the Docker daemon — 5 Reasons and How to Diagnose Each

Symptom: every docker command gets rejected

Cannot connect to the Docker daemon at unix:///var/run/docker.sock.
Is the docker daemon running?

One-line diagnosis: the docker CLI client is alive, but the dockerd daemon it talks to is not. The client reaches the daemon through a Unix socket (or TCP/SSH); if nothing answers there, this is the error. Note the difference from permission denied — that one means "the socket exists but you may not touch it"; this one means "the socket doesn't exist or nobody is behind it".

Five causes, ranked by frequency

1. The daemon isn't running (most common on Linux servers)

systemctl status docker
# ● docker.service - Docker Application Container Engine
#   Active: inactive (dead)   ← not running

sudo systemctl start docker
sudo systemctl enable docker   # and start it on boot while you're at it

Forgotten enable after a reboot, a service killed by an upgrade, or the OOM killer taking down dockerd — they all land here. Check the status before anything else.

2. Docker Desktop isn't open (macOS / Windows)

With Docker Desktop, the daemon runs inside a VM, but the CLI is separate — the App can be closed while the CLI still exists, producing the identical error. Start Docker Desktop and wait for the whale icon to settle.

3. WSL2: the distro integration got switched off

Using docker inside WSL2 on Windows requires Docker Desktop's integration for that distro (Settings → Resources → WSL Integration). An upgrade that resets the toggle is a frequent visitor:

# Restart WSL, then retry
wsl --shutdown

4. A broken daemon.json prevents the daemon from starting

When /etc/docker/daemon.json has a syntax error or an invalid field, systemctl start docker appears to succeed but actually fails. Get the real reason:

journalctl -u docker --since "10 minutes ago" | tail -20
# Common output: unable to configure the Docker daemon with file ...: invalid character

Fix the JSON (note: no trailing comma after the last key) and restart. This is the classic trap when configuring registry mirrors or log rotation.

5. Wrong docker context / missing rootless env var

docker context ls
# NAME       DESCRIPTION                          DOCKER ENDPOINT
# default *  Docker Engine at unix:///var/run/...   ← asterisk = current context

If the asterisk sits on a remote or stale context, even a perfectly healthy local daemon won't be reached: docker context use default.

Under rootless mode the socket lives in your user directory (/run/user/<uid>/docker.sock); a fresh SSH session without export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock will probe a system socket that doesn't exist.

The diagnostic route (two minutes, top to bottom)

# 1. Service status
systemctl status docker

# 2. Not active? Read the logs for the cause of death
journalctl -u docker -n 30

# 3. Service fine but still failing? Check socket and context
ls -l /var/run/docker.sock
docker context ls

# 4. Everything normal? Ask the daemon directly
sudo curl -s --unix-socket /var/run/docker.sock http://localhost/version | head -c 200

If step 4 returns JSON, the daemon is alive — the problem is your user's permission. See: Docker socket permission denied.

Telling the neighboring errors apart

ErrorMeaningGuide
Cannot connect to the Docker daemondaemon not running / unreachablethis post
permission denied ... docker.socksocket exists, your user lacks accesspermissions post
no space left on devicedaemon alive, disk fulldisk cleanup post
port is already allocateddaemon alive, port takenport conflict post

Rootless and user-mode daemons: the new startup paths

Docker Desktop (Mac/Windows): the daemon runs inside a utility VM — "cannot connect" means the VM/app is not started (launch the app; the CLI alone does not boot it), and CLI contexts can point at the wrong endpoint after upgrades (docker context ls; the desktop-linux context is the default — a stale context from a Docker Machine era lingers). Rootless Docker on Linux: the daemon runs per-user via systemd user units (loginctl enable-linger for the user so the daemon survives logout — the "it worked yesterday, daemon dead today" on shared boxes is linger missing). Podman compatibility: the docker CLI hitting podman's socket (an alias setup) has its own daemon-less model — docker context show names the active endpoint; knowing which daemon model your machine runs is step zero of every startup diagnosis.

The socket itself: permissions and existence

/var/run/docker.sock is the CLI-to-daemon contract: missing (fresh boot before the service, or a snap install with its own socket path — snap docker uses /run/snap.docker.sock, scripts referencing the classic path fail), permission-denied (user not in docker group — membership applies on next login, not immediately: newgrp docker or re-login; the chmod-666 workaround is root-equivalent-for-everyone and should never survive the day), or a stale socket file after a crash (the daemon fails to start because the old socket exists — systemd usually cleans, manual cases need the file removed before restart). ls -l on the socket and ss -lx | grep docker answer all three variants in ten seconds.

systemd units and the restart discipline

Modern Linux: dockerd runs as a systemd service (docker.service; containerd as its dependency socket/service — containerd dead takes docker with it: systemctl status containerd before blaming docker). The restart discipline: systemctl restart docker is safe for the daemon but kills running containers under the default live-restore=off (enable live-restore in daemon.json for containers to survive daemon restarts — the difference between a blip and an outage), and restart-loops (the service flapping) usually mean a config error in daemon.json — journalctl -u docker -n 50 shows the parse error in the first lines. The habit that prevents the whole class: a post-restart container check (docker ps against the expected list) wired into whatever restarts the daemon.

Checklist

  1. systemctl status docker — is the service active?
  2. macOS/Windows — is Docker Desktop running? Is WSL integration on?
  3. journalctl -u docker -n 30 — any daemon.json syntax errors?
  4. docker context ls — is the asterisk on default?
  5. rootless — is DOCKER_HOST set for this session?

After the daemon is back: confirm the fleet

A successful docker info only proves the socket answers. Follow with docker ps -a against the containers you expect, and check docker compose ls if stacks own the workloads. Live-restore off means a daemon restart may have exited containers that look “missing” rather than “daemon down.” Document which services auto-restart (restart: unless-stopped) so the next outage does not turn into a manual docker start scavenger hunt.

Triage notes

The five causes are ranked by probability: on Linux, "service not started" leads because a forgotten enable after reboot, a failed upgrade, and an OOM kill all land in that bucket; Docker Desktop comes second because its CLI exists independently while the daemon runs in a VM, so the error reads identically with the app closed. Step 4 of the diagnostic path — querying the daemon with curl — is a deliberate fork: getting JSON back means the daemon is alive and the problem is user permissions, the territory of the permission-denied article. The dividing line between the two pieces is one sentence: is the socket missing entirely, or present but off-limits to you?


Provided by ToolVault. Related tools: Dockerfile Generator, Run to Compose, Linux Cheatsheet. Related reading: Docker socket permissions, Port already in use (EADDRINUSE). See the homepage for more developer tools.