Skip to content

tmux & screen Footguns

Mistakes that kill processes, break workflows, or waste time debugging terminal issues.


1. SSH disconnect killing your process (not using tmux)

You SSH into a production server, start a database migration, and your VPN reconnects. The SSH connection drops. The migration process receives SIGHUP and dies mid-transaction. The database is in an inconsistent state. You just caused a production incident because you forgot to type tmux first.

Fix: Make it muscle memory — ssh server then immediately tmux new -s <task> before running anything. Add this to your SSH wrapper or shell alias:

# In your .bashrc on remote servers:
if [[ -z "$TMUX" ]] && [[ -n "$SSH_CONNECTION" ]]; then
    echo "WARNING: You are not in tmux. Run: tmux new -s $(whoami)"
fi

2. Nested tmux (prefix key collision)

You SSH into a remote server that has tmux running, from inside your local tmux. Now Ctrl-b goes to the local tmux, and you cannot control the remote one. You press Ctrl-b d to detach the remote session and accidentally detach your local session instead.

Fix: Send the prefix to the inner tmux by pressing it twice: Ctrl-b Ctrl-b <command>. Or use different prefix keys on local vs remote:

# On remote servers (~/.tmux.conf):
set -g prefix C-a

# On local machine (~/.tmux.conf):
set -g prefix C-b

Now Ctrl-b controls local, Ctrl-a controls remote. No collision.


3. tmux sessions lost after reboot

You reboot the server. All tmux sessions are gone. The server had no tmux-resurrect plugin, and the long-running screen sessions you assumed would survive a reboot did not. tmux sessions live in memory — they do not survive a reboot.

Fix: Install tmux-resurrect and tmux-continuum:

# In ~/.tmux.conf:
set -g @plugin 'tmux-plugins/tmux-resurrect'
set -g @plugin 'tmux-plugins/tmux-continuum'
set -g @continuum-restore 'on'

For critical long-running processes, use systemd services or nohup — not tmux — as the persistence mechanism.

Gotcha: Even with tmux-resurrect, the plugin saves window layouts and command strings — not actual process state. If you had a running database migration in a tmux pane, resurrect will try to re-run the command, not resume the original process. Only processes that are idempotent or designed to resume (like rsync) survive a resurrect safely. For anything stateful, systemd with Restart=on-failure is the correct tool.


4. Copy-paste not working (clipboard integration)

You select text in tmux copy mode, press Enter to copy, then Ctrl-V in another application. Nothing pastes. tmux has its own internal buffer that is separate from the system clipboard. On a headless server, there is no X11 clipboard at all.

Fix: Configure clipboard integration:

# For Linux with xclip:
bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "xclip -selection clipboard"

# For macOS:
bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "pbcopy"

# For SSH (no X11): use OSC 52 escape sequence support
set -g set-clipboard on
# Requires a terminal emulator that supports OSC 52 (iTerm2, Alacritty, kitty)

5. Mouse mode interfering with terminal selection

You enable set -g mouse on in tmux.conf. Now you cannot select text with your mouse to copy it — tmux intercepts all mouse events. Right-click paste stops working. Scrolling behaves differently.

Fix: Hold Shift while selecting to bypass tmux mouse handling and use the terminal's native selection. On macOS Terminal, hold Option instead. This is not obvious and trips up everyone at least once.

# Alternative: toggle mouse mode on/off with a keybinding
bind m set -g mouse on \; display "Mouse ON"
bind M set -g mouse off \; display "Mouse OFF"

6. screen vs tmux command confusion

You are in screen and press Ctrl-b % to split a pane. Nothing happens — screen uses Ctrl-a, not Ctrl-b. You are in tmux and press Ctrl-a d to detach. Nothing happens — tmux uses Ctrl-b by default. You have been on both systems today and your muscle memory is mixed up.

Fix: Standardize. Set tmux prefix to Ctrl-a (matching screen) so the same muscle memory works in both:

# ~/.tmux.conf
set -g prefix C-a
unbind C-b
bind C-a send-prefix

7. Zombie sessions consuming resources

You create tmux sessions for every task but never clean them up. tmux ls shows 40 sessions, most running abandoned processes that still consume CPU and memory. Some have open database connections holding locks.

Fix: Name your sessions and kill them when done:

# List sessions with creation time
tmux ls -F '#{session_name}: #{session_created_string} (#{session_windows} windows)'

# Kill old sessions
tmux kill-session -t old-task

# Kill ALL sessions except current
tmux kill-session -a

# Script to kill sessions older than 7 days
tmux ls -F '#{session_name} #{session_created}' | while read name created; do
    age=$(( $(date +%s) - created ))
    if (( age > 604800 )); then
        echo "Killing stale session: $name (age: $((age/86400))d)"
        tmux kill-session -t "$name"
    fi
done

8. tmux eating Ctrl-S (flow control)

You press Ctrl-S in tmux (maybe out of habit from an editor save). The terminal freezes. Nothing you type appears. It looks like tmux crashed or the SSH connection hung. Actually, Ctrl-S triggered XOFF flow control, pausing terminal output.

Fix: Press Ctrl-Q to resume (XON). Prevent it from happening:

# In your .bashrc or .zshrc:
stty -ixon   # Disable Ctrl-S/Ctrl-Q flow control entirely

9. Terminal size issues in shared sessions

Two engineers attach to the same tmux session. One has a 200x50 terminal, the other has 80x24. tmux shrinks to the smallest attached client. The engineer with the large terminal sees a small box surrounded by dots, wasting most of their screen.

Fix: Use aggressive-resize so windows resize to the largest client viewing that specific window (not the smallest client in the session):

# ~/.tmux.conf
setw -g aggressive-resize on

Or have the smaller client detach and reattach to a different session. Alternative: use tmux attach -t session with the -d flag to force-detach the other client.


10. Not naming sessions (cryptic tmux ls output)

You run tmux ls and see:

0: 3 windows (created Mon Mar 10 09:14:22 2025)
1: 1 windows (created Mon Mar 10 11:30:45 2025)
2: 5 windows (created Tue Mar 11 02:15:00 2025)

Which session has your database migration? Which one has the deploy watcher? You attach to each one, checking. You attach to the wrong one and accidentally type in a production console.

Fix: Always name sessions:

# Good
tmux new-session -s db-migration
tmux new-session -s deploy-prod
tmux new-session -s incident-4521

# Now tmux ls shows:
# db-migration: 1 windows ...
# deploy-prod: 3 windows ...
# incident-4521: 4 windows ...

Rename existing unnamed sessions:

# Inside tmux: Ctrl-b $  (then type the new name)
# From outside:
tmux rename-session -t 0 db-migration