docker exec vs docker attach: what is the difference?
docker exec and docker attach are both ways to interact with a running container, but they connect to different things. Misunderstanding which is which leads to a class of bugs where you accidentally kill production by pressing Ctrl+C in the wrong window.
Theory
TL;DR
docker exec= new process inside the container. The container's existing PID 1 keeps running independently.docker attach= connect to PID 1's stdio. You see what PID 1 sees (its stdin/stdout/stderr).- Killing your
execshell: only your shell exits. Container stays running. - Killing/Ctrl+C your
attachsession: PID 1 receives SIGINT. The container probably stops. - Detach from attach without killing: Ctrl+P then Ctrl+Q (must be
-itmode). - 99% of the time you want
exec.attachis rare.
What docker exec does
$ docker run -d --name web nginx
$ docker exec -it web sh
/ # ps aux
USER PID COMMAND
root 1 nginx: master process
nginx 29 nginx: worker process
root 45 sh # ← my shell, separate process
root 51 ps aux
/ # exit
# Container still running.The shell is process 45 inside the container. It runs alongside nginx (PIDs 1 and 29). Exit the shell → process 45 ends, nginx untouched, container still running.
What docker attach does
$ docker run -d --name web nginx
$ docker attach web
# (silent — nginx's stdio, with no current output)
# Press Ctrl+C
# nginx receives SIGINT → exits → container stopsYou are connected to nginx's stdio. Anything nginx prints, you see. Anything you type, nginx receives on stdin. Ctrl+C sends SIGINT to nginx. nginx exits. Container ends.
For debugging, this is almost never what you want.
Side-by-side
docker exec | docker attach | |
|---|---|---|
| Creates a process | yes (new) | no (connects to PID 1) |
| Kills container on Ctrl+C | no | yes (sends SIGINT to PID 1) |
| Ctrl+P, Ctrl+Q to detach safely | n/a | yes |
| Use for | debugging, inspection, ad-hoc commands | REPLs as PID 1, console apps |
| Common mistake | none really | accidentally killing prod |
Detaching from attach
The escape sequence to leave attach without killing PID 1:
Ctrl+P, Ctrl+Q
Must be in -it mode (interactive + TTY). Without -t, there is no terminal sequence to interpret; without -i, stdin is closed. Without escape sequence, your only options are Ctrl+C (kills container) or kill the docker process from outside.
In shells that override Ctrl+P (some tmux configs), you may need to remap before attaching.
When attach is actually useful
REPLs as PID 1
docker run -d --name nodejs node:22 node
# nodejs running as PID 1, REPL waiting for input
docker attach nodejs
> 1+1
2
> .exit
# Ctrl+P, Ctrl+Q to detach insteadA Python or Node REPL run as PID 1 only takes input via attach. exec would spawn a new shell, which is not what you want.
Console-based apps
Apps that interact via stdio as their primary interface (chess servers, console games, certain admin tools) need attach.
Watching live PID 1 output
docker attach web
# nginx access log streams in real timeThough docker logs -f web is usually a better choice — same effect, no risk of killing.
Common mistakes
Using attach when you wanted exec
# WRONG
docker attach web # connects to nginx's stdio
# Press Ctrl+C → kills nginx → container stops → outage
# RIGHT
docker exec -it web sh # new shell
# Press Ctrl+D (or exit) → shell ends → container untouchedThe most common attach mistake is treating it like exec. Same intuition ("connect to running container"), very different consequences.
Forgetting -it with attach
docker attach --no-stdin web # disables stdin
# can no longer Ctrl+P, Ctrl+Q to detach (no TTY)
# only Ctrl+C, which killsIf you must attach without TTY, accept that Ctrl+C is your only exit. Better: just don't.
Using --sig-proxy=false in attach without understanding
docker attach --sig-proxy=false web
# Ctrl+C now does NOT propagate to PID 1 — container survivesA workaround for safer attach. But if you need this, you probably wanted exec anyway.
Trying to attach to a stopped container
$ docker attach stopped-web
Error: container is not runningAttach requires running. Use docker start -ai stopped-web to revive an exited container with stdio attached (different but related).
Real-world usage
execfor 99% of debugging: shell into a running container, run a one-off command, inspect files, check env. Safe and standard.attachspecifically for: interacting with REPLs as PID 1 (rare), console apps where stdio is the API (rare), watching live output withoutdocker logs(rare; logs are usually better).- Never
attachto a production web server you do not want killed. Usedocker logs -finstead.
Follow-up questions
Q: Why does Ctrl+C kill the container with attach but not with exec?
A: With attach, you are connected to PID 1's stdio. Ctrl+C sends SIGINT to PID 1 (the main process). PID 1 exits, container exits. With exec, your shell is a separate process; Ctrl+C kills the shell, not PID 1.
Q: Can multiple users attach to the same container?
A: Yes — they all see PID 1's output and share stdin. Acts like a screen session. Useful for collaborative debugging; risky because anyone could Ctrl+C accidentally.
Q: What is the difference between docker attach and docker exec -it container bash?
A: Attach connects to existing PID 1's stdio. Exec creates a new bash process inside the container. The new bash is independent; PID 1 is shared.
Q: What does docker run -d then docker attach give me vs docker run (no -d)?
A: Same outcome (you see PID 1's output). The -d + attach combo is useful when you want to start detached, do other things, then attach later. docker run without -d is attach-by-default.
Q: (Senior) When would you write a custom container that requires docker attach over docker exec?
A: When the container's purpose IS to interact via stdio as the primary interface — like a custom REPL, an interactive admin tool that the user runs occasionally rather than as a daemon, or a game server with admin console. Even then, modern designs prefer HTTP or gRPC APIs over stdio attachment for usability and multi-user support. Pure-stdio interfaces are increasingly rare; if you find yourself reaching for attach, ask whether your design might be a relic.
Examples
Safe debugging with exec
# Production web server. Investigate WITHOUT risking outage.
docker exec -it web sh
/ # cat /etc/nginx/nginx.conf
/ # netstat -tlnp
/ # ps aux
/ # exit
# nginx never noticed; uptime preserved.Risky live tail with attach
# DO NOT do this in production
docker attach prod-web
# Streams live access logs.
# Accidental Ctrl+C → SIGINT → nginx exits → 502 for users.
# Better:
docker logs -f prod-web # same output, safeDetach demo
$ docker run -d --name pyrepl python:3.13 python
# Python REPL waiting in background as PID 1
$ docker attach pyrepl
>>> 2 + 2
4
>>> # Now press Ctrl+P, then Ctrl+Q
read escape sequence
$ docker ps --filter name=pyrepl
STATUS NAMES
Up 2 minutes pyrepl # still runningDetach safely; container keeps the REPL alive; you can re-attach later.
When attach is actually needed
# Custom container designed as an interactive tool
docker run -d --name console myorg/admin-console:1.0
docker attach console
admin> help
admin> reset --user 42
admin> exit
# Custom 'exit' command tells the app to shut down.If the app's design is "talk to me via stdio", attach is the only way. But this design is uncommon.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.
Comments
No comments yet