Skip to content
Shell & TerminalDeep Dive Published Updated 5 min readViews unavailable

How Terminal Multiplexers Keep Sessions Alive

PTYs and a persistent server process explain how tmux and screen survive a dropped SSH connection, not just several shells in one window.

When a normal SSH session disappears, its shell usually loses the terminal that connected it to the user. A multiplexer such as tmux changes that ownership model: the shell belongs to a long-lived local server, while the visible terminal is only a replaceable client.

The kernel object behind a terminal window

Modern terminal emulators and SSH daemons use a pseudoterminal, or PTY. A PTY has a master side and a slave side. The terminal emulator controls the master; a shell opens the slave as its controlling terminal. Bytes written by the shell become output, while bytes sent to the master become input after the terminal driver’s line discipline processes them.

Interactive programs do not need to know whether the other end is a physical serial terminal, an SSH connection, or a graphical terminal emulator. They ask the PTY for its size and settings, emit escape sequences, and receive signals such as SIGWINCH when the window changes.

Where the multiplexer fits

Starting tmux creates, or contacts, a server process. For every pane, that server allocates another PTY and starts the requested shell on its slave side. The server owns the master sides and continually reads their output. A tmux client then renders one or more panes onto the user’s current terminal.

This adds a layer:

terminal or SSH -> tmux client -> tmux server -> pane PTY -> shell/program

The pane’s shell is therefore not directly attached to the SSH PTY. Detaching closes the client connection but leaves the server, pane PTY, and shell intact. Reattaching creates a new client and redraws the saved screen state.

Sessions, windows, and panes are server state

A session is a named collection of windows; a window is a layout of panes; a pane corresponds to a PTY and foreground process group. These are tmux concepts rather than kernel terminal types. Multiple clients can attach to the same session, and the server decides how to map its virtual screen onto clients with different dimensions.

The server also interprets the prefix key before ordinary input reaches a pane. Commands such as splitting, selecting, or detaching manipulate server state; other keystrokes are forwarded to the active pane’s PTY.

What persistence does and does not mean

The session survives a lost network connection because the server runs on the remote host. It does not survive that host rebooting, the tmux server being killed, or its user account losing all processes. A multiplexer also is not a job scheduler: important unattended work should still have durable logs, explicit restart policy, and an appropriate service manager.

What happens when attached clients disagree on terminal size

Because a pane’s PTY has exactly one size at any given moment, but multiple clients can attach to the same session with genuinely different terminal window dimensions, the server has to pick a single size to actually present to the program running inside. tmux’s window-size option controls how: the default, smallest, constrains the window to the smallest attached client’s dimensions, padding any unused space on larger clients with a filler character rather than letting the window grow to fill them; largest does the reverse, sizing to the biggest attached client and letting smaller ones see only a portion of it; latest instead tracks whichever client was most recently typed into, resizing dynamically as attention shifts between clients. This is a real architectural consequence of the client/server split covered above, not an incidental setting — a single shared pane fundamentally cannot simultaneously be two different sizes, so something has to give when clients disagree, and window-size is the explicit policy for deciding what.

Talking to the multiplexer as a program, not a display

tmux also supports control mode, entered by starting a client with -CC, in which it stops rendering a text-mode interface entirely and instead exchanges a structured, line-based protocol over stdin/stdout — commands in, asynchronous notifications (prefixed with %) out, describing exactly what changed and where. This is what iTerm2’s own tmux integration is built on: iTerm2 launches tmux in control mode and translates the protocol’s window and pane events into native iTerm2 tabs and split panes, giving a session tmux’s own persistence and multi-client reattachment underneath what looks and feels like an entirely native local interface, rather than a text-mode application rendered inside a single pane. It’s a concrete illustration of how cleanly the multiplexer’s server-side session state is separated from any particular way of displaying it — a text-mode client, a GUI translating the same protocol, and a scripted automation tool can all drive the identical underlying session through interfaces suited to each.

Why a pane’s shell doesn’t die the moment you log out

An ordinary shell process shares a controlling terminal with whatever originally started it — log out of a plain SSH session, and the kernel sends SIGHUP to every process still attached to that now-closing controlling terminal, which is why an unprotected background job normally dies the instant its parent session ends. A multiplexer sidesteps this entirely through the same server/pane-PTY architecture already described above: each pane’s shell has that pane’s own PTY as its controlling terminal, not the SSH session’s, and that pane PTY belongs to the long-running tmux server process rather than to your login session at all. When the SSH connection drops, SIGHUP is delivered to whatever’s actually attached to that connection’s terminal — the tmux client, which simply exits — while the server and every pane’s shell, each attached to a separate PTY the server itself owns, were never in that signal’s path to begin with. Session persistence here isn’t a special “ignore SIGHUP” behavior tmux has to implement defensively; it’s a structural consequence of which process owns which controlling terminal, which is exactly why detaching cleanly and having a connection drop out from under you produce the identical, harmless result from the pane’s perspective.

Related:

Sources:

Comments