Skip to main content

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 exec shell: only your shell exits. Container stays running.
  • Killing/Ctrl+C your attach session: PID 1 receives SIGINT. The container probably stops.
  • Detach from attach without killing: Ctrl+P then Ctrl+Q (must be -it mode).
  • 99% of the time you want exec. attach is rare.

What docker exec does

bash
$ 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

bash
$ 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 stops

You 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 execdocker attach
Creates a processyes (new)no (connects to PID 1)
Kills container on Ctrl+Cnoyes (sends SIGINT to PID 1)
Ctrl+P, Ctrl+Q to detach safelyn/ayes
Use fordebugging, inspection, ad-hoc commandsREPLs as PID 1, console apps
Common mistakenone reallyaccidentally 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

bash
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 instead

A 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

bash
docker attach web # nginx access log streams in real time

Though docker logs -f web is usually a better choice — same effect, no risk of killing.

Common mistakes

Using attach when you wanted exec

bash
# 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 untouched

The most common attach mistake is treating it like exec. Same intuition ("connect to running container"), very different consequences.

Forgetting -it with attach

bash
docker attach --no-stdin web # disables stdin # can no longer Ctrl+P, Ctrl+Q to detach (no TTY) # only Ctrl+C, which kills

If 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

bash
docker attach --sig-proxy=false web # Ctrl+C now does NOT propagate to PID 1 — container survives

A workaround for safer attach. But if you need this, you probably wanted exec anyway.

Trying to attach to a stopped container

bash
$ docker attach stopped-web Error: container is not running

Attach requires running. Use docker start -ai stopped-web to revive an exited container with stdio attached (different but related).

Real-world usage

  • exec for 99% of debugging: shell into a running container, run a one-off command, inspect files, check env. Safe and standard.
  • attach specifically for: interacting with REPLs as PID 1 (rare), console apps where stdio is the API (rare), watching live output without docker logs (rare; logs are usually better).
  • Never attach to a production web server you do not want killed. Use docker logs -f instead.

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

bash
# 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

bash
# 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, safe

Detach demo

bash
$ 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 running

Detach safely; container keeps the REPL alive; you can re-attach later.

When attach is actually needed

bash
# 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 ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Comments

No comments yet