Docker Error Guide: 'cannot stop container: permission denied' — Fix Daemon and Cgroup Signal Failures
Fix Docker 'cannot stop container permission denied': diagnose docker socket access, rootless and SELinux/AppArmor policies, stuck cgroups, and kill signals the runtime cannot deliver.
- #docker
- #troubleshooting
- #errors
- #permissions
Overview
Docker returns this when the daemon accepts a stop request but the underlying runtime cannot deliver the kill signal to the container’s processes:
Error response from daemon: cannot stop container 5c1f9b0a2e83: permission denied
There are two distinct flavors. Either the client cannot talk to the daemon at all (a socket-permission problem on the user’s side), or the daemon can reach the runtime but a security policy or a broken cgroup prevents it from signalling the container’s PID 1. The word permission points at access control — on the socket, in SELinux/AppArmor, or in the cgroup hierarchy.
Symptoms
docker stop <id>ordocker rm -f <id>returnscannot stop container ... permission denied.- The container stays in
Up(orRemoval In Progress) no matter how many times you stop it. - Non-root users get
permission denied while trying to connect to the Docker daemon socketon every command. dmesgshows AppArmor/SELinux denials around the container’s runtime.
Common Root Causes
- Docker socket permissions — the user is not in the
dockergroup, so the client cannot reach/var/run/docker.sock. - SELinux or AppArmor policy — a security module denies the runtime the right to send signals to the container.
- Stuck or corrupted cgroup — the container’s cgroup is in a bad state, so runc cannot deliver
SIGTERM/SIGKILL. - Rootless Docker limitations — a rootless daemon lacks privileges to signal certain processes.
- Unkillable process state — PID 1 is stuck in uninterruptible sleep (
Dstate) on a hung mount or I/O. - Daemon/runtime mismatch or corruption after an upgrade.
Diagnostic Workflow
First separate a client-side socket problem from a daemon-side signal problem. If ordinary commands fail too, it is the socket:
docker ps # if this also says permission denied -> socket issue
ls -l /var/run/docker.sock
id -nG | tr ' ' '\n' | grep -x docker # are you in the docker group?
If docker ps works but stop does not, look at the container and the runtime. Check its state and try an explicit kill:
docker inspect --format '{{.State.Status}} pid={{.State.Pid}}' 5c1f9b0a2e83
sudo docker kill -s SIGKILL 5c1f9b0a2e83
Inspect the daemon and kernel for policy denials:
journalctl -u docker --since '10 min ago' | grep -i '5c1f9b0a2e83\|permission\|apparmor'
dmesg | tail -30 | grep -i 'apparmor\|selinux\|denied'
Check whether PID 1 is wedged in uninterruptible sleep on the host:
ps -o pid,stat,cmd -p $(docker inspect --format '{{.State.Pid}}' 5c1f9b0a2e83)
A D in the STAT column means the process is blocked in the kernel and no signal will land until the I/O clears.
Example Root Cause Analysis
An operator could run docker ps but every docker stop web returned cannot stop container ... permission denied. Because listing worked, the socket was fine — this was a daemon-side signal problem.
The daemon log pointed at the security module:
journalctl -u docker --since '5 min ago' | grep -i apparmor
# apparmor="DENIED" operation="signal" profile="docker-default" ...
A custom AppArmor profile applied to the container was denying the signal capability, so runc could not deliver SIGTERM. The immediate remediation was to force-kill through the runtime and then correct the profile:
sudo docker kill -s SIGKILL web
The durable fix was to update the AppArmor profile to permit signalling within docker-default (or run the container with the standard profile), after which normal docker stop worked again. When the cause is instead a stuck cgroup, a daemon restart (sudo systemctl restart docker) clears the wedged state.
Prevention Best Practices
- Add operators to the
dockergroup (or use rootless Docker deliberately) so socket permission errors never masquerade as stop failures. - Test custom SELinux/AppArmor and seccomp profiles against a full container lifecycle — start, exec, and stop — before rolling them out.
- Keep the daemon and runc/containerd versions in sync, and restart the daemon after upgrades to avoid a stale runtime.
- Avoid mounts (NFS, network storage) that can hang PID 1 in uninterruptible sleep; add timeouts.
- Standardize container security settings using the Docker stack guide and validate build-time config with the Dockerfile validator.
Quick Command Reference
docker ps # works? -> daemon-side; fails? -> socket-side
ls -l /var/run/docker.sock; id -nG | grep docker
docker inspect --format '{{.State.Status}} {{.State.Pid}}' <id>
sudo docker kill -s SIGKILL <id> # force the signal via the runtime
journalctl -u docker --since '10 min ago' | grep -i 'apparmor\|permission'
dmesg | tail -30 | grep -i 'denied'
Conclusion
cannot stop container: permission denied has two very different roots. If every Docker command fails, fix the socket permissions — add the user to the docker group. If only stop fails, the daemon cannot signal the container: check for SELinux/AppArmor denials in the logs, a wedged cgroup, or a PID 1 stuck in D state. Force the kill through the runtime to regain control, then correct the security profile or restart the daemon so ordinary stops work again.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.