How to Stop a Docker Container (3 Ways)
Learn how to stop a Docker container cleanly with docker stop, force-quit with docker kill, and freeze with docker pause — with real commands and output.
FlowQL Team
AI Search Optimization Experts
You typed docker stop and nothing happened. Or you're not sure whether to use docker stop, docker kill, or something else entirely. Either way, this guide covers the three main ways to stop a Docker container, when each one applies, and what to do when a container refuses to die.
Docker gives you several options for stopping containers because different situations call for different levels of force. A container running a web server mid-request needs a different treatment than a zombie process with a frozen event loop. Getting this wrong — reaching for docker kill when docker stop would do — can corrupt data or leave your application in a state that's harder to diagnose on the next start.
docker stop: The Clean Shutdown
What does docker stop actually do?
docker stop is the right command for almost every normal shutdown. It sends a SIGTERM signal to the main process inside the container (PID 1), waits up to 10 seconds for the process to exit on its own, then sends SIGKILL if it hasn't stopped yet. The container gets a chance to flush buffers, close database connections, and finish in-flight requests before it goes away.
# Stop a container by ID
docker stop a3f8c2b1d4e9
# Stop a container by name
docker stop my-postgres
# Stop and give the container 30 seconds instead of the default 10
docker stop --time 30 my-postgres
The --time flag (short form: -t) is useful for containers running slow jobs — database flushes, large file writes, or connection drains that need more than the default 10-second window.
After you run docker stop, the container status changes from Up to Exited. You can confirm it worked:
$ docker stop my-postgres
my-postgres
$ docker ps -a --filter name=my-postgres
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d7e4f1a2b3c9 postgres "docker-entrypoint.s…" 2 hours ago Exited (0) 4 seconds ago my-postgres
Exit code 0 means the process shut down cleanly. If you see exit code 137, the container was killed with SIGKILL — either the stop timeout expired, or something else sent the signal.
You can also stop multiple containers in a single command by passing several names or IDs:
# Stop multiple specific containers at once
docker stop api-server db-container cache-server
Docker starts the shutdown on all of them simultaneously rather than sequentially, so the total wait time is the longest individual shutdown, not the sum of all of them.
The official docker stop reference covers every flag in detail.
docker kill: Force-Stop a Frozen Container
When should you use docker kill instead of docker stop?
Use docker kill when a container is frozen, stuck in an infinite loop, or simply ignoring SIGTERM. It bypasses the graceful period and goes straight to SIGKILL, which the kernel handles — the process has no chance to intercept it.
# Force-kill a container immediately
docker kill my-stuck-app
# Send a specific signal instead of SIGKILL
docker kill --signal SIGTERM my-stuck-app
# Kill by container ID prefix (first 4+ characters is enough)
docker kill a3f8
The output is just the container name or ID echoed back:
$ docker kill my-stuck-app
my-stuck-app
A few important caveats. docker kill does not remove the container — the container still exists in Exited state and can be restarted. Data written to volumes survives. Data that was only in the container's writable layer and hadn't been flushed may be lost, which is why you reach for docker stop first.
One less obvious use case: you can use docker kill to send signals other than SIGKILL. For example, sending SIGHUP to a process like Nginx or HAProxy triggers a live config reload without stopping the container at all. That makes docker kill --signal SIGHUP my-nginx a lightweight alternative to restarting the container just to pick up a config change.
The docker kill reference lists every signal you can send if you need something other than SIGKILL.
docker pause and unpause: Freeze Without Stopping
What is docker pause used for?
docker pause suspends all processes inside a container using Linux cgroups freezer. The container stays alive — its filesystem, network, and memory are untouched — but all execution stops. This is useful for resource-constrained environments where you want to temporarily free CPU without losing container state.
# Pause a running container
docker pause my-worker
# Check its status — shows "Paused"
docker ps --filter name=my-worker
# Resume it exactly where it left off
docker unpause my-worker
$ docker pause my-worker
my-worker
$ docker ps --filter name=my-worker
CONTAINER ID IMAGE COMMAND STATUS NAMES
b1c2d3e4f5a6 node "node app.js" Up 14 minutes (Paused) my-worker
Pause is not a substitute for docker stop. Paused containers still consume memory. They will not respond to network requests. And unlike stopped containers, paused containers cannot be removed with docker rm — you must unpause or kill them first. The docker pause reference has the full details.
Stop All Running Containers at Once
The most common one-liner for clearing out all running containers:
# Stop every running container
docker stop $(docker ps -q)
# Verify nothing is left running
docker ps
docker ps -q outputs only container IDs, one per line. Bash command substitution passes them all as arguments to docker stop in a single call.
If you're running Docker on Windows with PowerShell:
docker ps -q | ForEach-Object { docker stop $_ }
Want to stop and then remove every container in one shot? Chain it:
# Stop all running containers, then remove all stopped containers
docker stop $(docker ps -q) && docker container prune -f
The -f flag on docker container prune skips the confirmation prompt, useful in scripts. Be careful — prune also removes containers that were already stopped before you ran this command.
If you're working with multi-container apps defined in a Compose file, docker compose down is cleaner than mass-stopping individual containers — it also removes the network and optionally the volumes. See the docker compose down docs for all options. For more on managing volumes in Compose setups, check out Docker Compose volumes explained.
docker stop vs docker kill: When to Use Each
Both commands stop a container. The difference is how much respect they show for the process running inside.
| Command | Signal sent | Waits for graceful exit? | Use when |
|---|---|---|---|
| docker stop | SIGTERM → SIGKILL | Yes (default 10s) | Normal shutdown — container can clean up |
| docker kill | SIGKILL (default) | No | Container is frozen or ignoring SIGTERM |
| docker pause | cgroup freeze | N/A — process suspended | Temporarily free CPU, preserve state |
| docker stop -t 0 | SIGTERM + immediate SIGKILL | No (0s timeout) | Equivalent to kill, but via stop command |
The practical rule: always try docker stop first. If it hangs for longer than your timeout, escalate to docker kill. Running docker kill on a healthy container works, but you risk data loss if the container was in the middle of writing something important.
Another way to think about it: docker stop is polite, docker kill is brutal. For production workloads, always be polite first. The 10-second wait costs you almost nothing in normal operation, and it can save you hours of data recovery when something goes wrong.
For database containers in particular — Postgres, MySQL, Redis — always use docker stop with a generous timeout. An ungraceful kill of a database can leave files in an inconsistent state that requires recovery on the next start. For a deeper look at running Postgres in Docker, see the Postgres Docker guide.
What to Do When a Container Won't Stop
Why won't my container stop?
This is the frustrating scenario: you run docker stop my-app and the terminal just hangs for 10 seconds, then the container is still running. Here's what's actually happening and how to fix it.
The process is ignoring SIGTERM. Many processes — especially those started with shell scripts (CMD ["sh", "-c", "node app.js"]) — do not forward signals to child processes. PID 1 in the container is the shell, not your app, and the shell eats the SIGTERM without passing it on. Fix: use exec form in your Dockerfile (CMD ["node", "app.js"]) so your application is PID 1 and receives the signal directly. The Docker best practices guide covers this pattern.
The container has a restart policy. If a container is configured with --restart always or --restart unless-stopped, Docker will restart it after docker stop. The container appears to be running again immediately. Fix:
# Remove the restart policy, then stop
docker update --restart=no my-app
docker stop my-app
The process is truly stuck. Some containers get into a state where even SIGKILL doesn't work — usually because of zombie processes or kernel-level hangs. In this case:
# Find the container's PID on the host
docker inspect --format '{{.State.Pid}}' my-stuck-app
# Kill it at the host level
sudo kill -9 <pid>
If you're hitting persistent container issues that go beyond a simple stop command — particularly if containers are hanging, crashing at startup, or behaving differently between environments — that's often a signal the problem is deeper in your Docker setup or application code. If you're spending more time debugging Docker than shipping features, a 30-minute session with a senior engineer at FlowQL can cut through the confusion faster than another hour of Stack Overflow.
The volume or bind mount is causing issues. If your container exits with errors rather than cleanly stopping, and you're using Docker volumes or bind mounts, the issue might be data-related rather than process-related. The Supabase connection refused guide covers a related class of problems — containers that start but won't respond — that often share root causes with stop/restart issues.
The container was started with docker run -d but has no stop signal defined. If your image's Dockerfile does not include a STOPSIGNAL instruction, Docker defaults to SIGTERM. But if your entrypoint script uses exec to hand off to your app, make sure that exec is in place — without it, your shell becomes PID 1, not your app, and the signal never reaches the process that needs to handle it.
# Good: your app is PID 1 and receives SIGTERM directly
CMD ["node", "server.js"]
# Risky: the shell is PID 1 and may not forward the signal
CMD ["sh", "-c", "node server.js"]
You can also define a custom stop signal per container at runtime:
# Tell Docker to send SIGINT instead of SIGTERM on docker stop
docker run --stop-signal SIGINT --name my-app my-image
Check the container logs before you kill it. Always grab the last 50 lines before force-killing, so you have something to work with afterward:
# Get the last 50 lines of logs before force-stopping
docker logs --tail 50 my-stuck-app
docker kill my-stuck-app
For build and deploy issues that surface after a container restart — like configuration changes that don't take effect — the Vercel build failed guide covers the same class of environment mismatch problems in a different context.
Conclusion
Stopping a Docker container comes down to three tools with three different levels of force:
docker stop— the default. Sends SIGTERM, waits up to 10 seconds, then SIGKILL. Use this almost always.docker kill— no waiting. Sends SIGKILL immediately. Use whendocker stophangs or the container is frozen.docker pause/docker unpause— freezes execution without stopping. Use when you need to free CPU temporarily without losing state.
When containers won't stop, the cause is almost always one of three things: a process that ignores SIGTERM, a restart policy keeping the container alive, or a genuinely stuck process that needs to be killed at the host level.
For most day-to-day work, docker stop <name> is all you need. Reach for docker kill only when docker stop fails, and check docker logs before you do — the logs almost always tell you why the container got stuck in the first place.
Still blocked?
This fix didn't work for your setup? Get a senior engineer on your screen in 30 minutes — fixed or refunded.
Reserve My Spot →Get a senior engineer on your screen.
30-minute live screen-share sessions with a vetted senior dev. Fixed or fully refunded — no questions asked.
No spam. Just a heads-up when sessions open.
Related Articles
Docker Compose Volumes: Mount, Persist & Share Data
Master docker compose volumes with working syntax, named volumes, bind mounts, and fixes for the most common data-loss and permission errors.
Fix: supabase_internal_image_registry Error — Use Docker Hub When ECR Is Blocked
Getting 'supabase_internal_image_registry' errors when ECR is blocked? Set SUPABASE_INTERNAL_IMAGE_REGISTRY=docker.io to pull from Docker Hub. Works in terminal, docker-compose, and CI/CD.
supabase_internal_image_registry: use Docker Hub when public.ecr.aws is blocked
supabase start failing because public.ecr.aws is blocked? Set SUPABASE_INTERNAL_IMAGE_REGISTRY=docker.io to pull from Docker Hub instead. Exact command included.