Docker Container Keeps Restarting? Find the Cause and Fix It
A container that keeps restarting is a process that exits, followed by Docker's restart policy (always, unless-stopped or on-failure) starting it again. Docker is doing its job; the question is why the process exits. The answer is almost always in three places: the exit code, the last log lines and memory.
docker ps -a -f status=restarting # which containers loop
docker inspect -f '{{.State.ExitCode}} {{.State.OOMKilled}} {{.RestartCount}}' app
docker logs --tail 50 app # the error before the exit
Step 1: Read the Exit Code
docker inspect -f 'exit={{.State.ExitCode}} oom={{.State.OOMKilled}} restarts={{.RestartCount}} error={{.State.Error}}' app
| Exit code | What it usually means | Where to look |
|---|---|---|
0 |
The main process finished normally. A service container should not do that - the command runs once and exits (wrong CMD, process daemonised itself, script without a foreground process) |
CMD/ENTRYPOINT, run the service in the foreground |
1 |
Application error | docker logs - stack trace, missing config, failed connection |
2 |
Shell misuse or bad arguments | entrypoint script, command-line flags |
125 |
Docker could not run the container (bad docker run option) |
the error printed by Docker itself |
126 |
Command found but not executable | file permissions, chmod +x on the entrypoint |
127 |
Command not found | typo in CMD, binary missing in the image, wrong PATH |
137 |
SIGKILL - OOM killer or docker kill |
OOMKilled, memory limit, dmesg |
139 |
Segmentation fault | binary built for a different CPU or libc, native extension crash |
143 |
SIGTERM - stopped from outside | something else is stopping it: deploy script, orchestrator, healthcheck tooling |
Step 2: Read the Logs From Before the Crash
docker logs --tail 100 app # last lines, including the previous run
docker logs --since 10m -t app # with timestamps
docker logs app 2>&1 | grep -iE 'error|fatal|exception|denied|refused' | tail -20
Logs survive restarts, so the error from the previous run is still there. Typical findings:
connection refused/could not connect to server- the container starts before its database or another dependency is ready. Add retries in the application ordepends_onwithcondition: service_healthyin Compose.permission denied- a mounted volume belongs to a different UID than the user inside the container.address already in use- another process or container already binds the port.exec format error- the image was built for another CPU architecture (arm64 vs amd64).- missing environment variable or config file - compare
docker inspect -f '{{json .Config.Env}}' appwith what the application expects.
Step 3: Check for OOM Kills
docker inspect -f '{{.State.OOMKilled}} limit={{.HostConfig.Memory}}' app
docker stats --no-stream app
dmesg -T | grep -iE 'killed process|out of memory' | tail
OOMKilled=true (or exit code 137 with an OOM line in dmesg) means the container used more memory than its limit, or the host ran out of memory. Either raise the limit (docker update --memory 1g --memory-swap 1g app, or mem_limit in Compose), reduce the application's memory use, or move other workloads off the host.
Step 4: Stop the Loop While You Debug
A container that restarts every few seconds is hard to inspect. Pause the policy, keep the evidence, then start it by hand:
docker update --restart=no app # stop automatic restarts
docker start -a app # run in the foreground and watch it fail
To look inside an image whose process dies immediately, override the entrypoint:
docker run --rm -it --entrypoint sh myimage:tag
Then run the original command manually and read the error. When you are done, restore the policy with docker update --restart=unless-stopped app.
Step 5: Healthcheck-Driven Restarts
Plain Docker does not restart a container because it is unhealthy - it only marks it. Restarts on failed healthchecks come from an orchestrator (Swarm, Kubernetes liveness probes) or tools such as autoheal. If those restart your container:
- give slow-starting applications a
start_period, - make the check test the application, not just an open port,
- keep
timeoutabove the application's normal response time under load.
Which Restart Policy to Use
| Policy | Restarts when | Use for |
|---|---|---|
no |
Never | Debugging, one-off jobs |
on-failure[:N] |
Exit code is non-zero, at most N times | Workers that should give up after repeated failures |
unless-stopped |
Always, unless you stopped it manually | Most long-running services |
always |
Always, also after a manual stop when the daemon restarts | Services that must come back no matter what |
Docker increases the delay between restarts (starting at 100 ms and doubling, up to one minute), so a looping container spends most of its time waiting - which is why docker ps shows Restarting (1) 8 seconds ago rather than a running process.
Common Causes at a Glance
| Symptom | Likely cause |
|---|---|
| Exits with 0 a second after start | Command does not run in the foreground |
| Exit 1 after a deploy, old image worked | New config/env variable, migration, changed dependency |
Exit 137, OOMKilled=true |
Memory limit too low or a memory leak |
| Loops only after host reboot | Starts before the database or a network mount is ready |
| Exit 127 / 126 | Entrypoint missing or not executable |
| Exit 139 | Wrong architecture or native library crash |
Get Alerted Before Users Notice
A restart loop can run unnoticed for hours if the service behind it is behind a load balancer or a queue. Two checks catch it:
# containers restarting right now
docker ps -f status=restarting --format '{{.Names}} {{.Status}}'
# containers that restarted more than 5 times
for c in $(docker ps -aq); do docker inspect -f '{{.Name}} {{.RestartCount}}' "$c"; done | awk '$2 > 5'
In Zuzia, add one of these commands as a scheduled task on the server: any output means a container is looping, and the output of every run is kept with an AI summary, so you can see when the loop started. An HTTP or port check on the service behind the container alerts you by email, Slack or SMS when users are affected. For the general status check of all containers, see how to list and check running Docker containers.
FAQ
Why does my Docker container keep restarting?
Its main process exits and the restart policy starts it again. Check the exit code with docker inspect -f '{{.State.ExitCode}}' <name> and the last lines of docker logs <name> - together they explain most loops.
How do I stop a container from restarting?
docker update --restart=no <name> disables the policy; docker stop <name> then stops it. In Compose, set restart: "no" and run docker compose up -d again.
How do I debug a container that crashes immediately?
Disable the restart policy, then run docker start -a <name> to see the output in the foreground, or start the image with a shell: docker run --rm -it --entrypoint sh <image>.
How can I tell if the OOM killer stopped my container?
docker inspect -f '{{.State.OOMKilled}}' <name> returns true, the exit code is 137 and dmesg shows an "Out of memory: Killed process" line.
What is the difference between always and unless-stopped?
Both restart the container whenever it exits. After a manual docker stop followed by a Docker daemon restart, always starts the container again and unless-stopped leaves it stopped.
Does Docker restart unhealthy containers?
No. Docker only marks the container as unhealthy. Restarts on failed healthchecks come from Swarm, Kubernetes or an external tool.
Can a restart loop affect other containers?
Yes. A looping container can hold a port, fill the disk with logs, use CPU on every start and break services that depend on it. Limit log size with --log-opt max-size=10m and fix the loop rather than relying on the restart policy.