I have been using SSH almost every day for the past twelve years. I manage servers for a living. I have typed ssh user@host more times than I have said “good morning” to my family. And last week, I discovered that SSH has a secret in-session menu that I never knew existed.
Twelve years. Every day. And I missed this.
If you are an experienced sysadmin and you already know about the SSH escape character, congratulations, you are better than me. Feel free to read this anyway and feel smug. For the rest of you — and based on the reactions when this topic hit the front page of Hacker News this week, there are a lot of you — buckle up.
The Escape Character: Your Secret Backdoor
While you are connected to a remote server via SSH, press Enter, then type ~?. Go ahead. Try it right now if you have a terminal open.
What you will see is something like this:
Supported escape sequences:
~. - terminate connection (and any multiplexed sessions)
~B - send a BREAK to the remote system
~C - open a command line
~R - request rekey
~V/v - decrease/increase verbosity (LogLevel)
~^Z - suspend ssh
~# - list forwarded connections
~& - background ssh (when waiting for connections to terminate)
~? - this message
~~ - send the escape character by typing it twice
That is a hidden menu. Inside your SSH session. That has been there the entire time.
My colleague Jake saw me discover this in real time during a pair debugging session last Tuesday. His exact words were: “How do you not know about this? You literally wrote a guide about SSH tunneling.” To which I responded with a noise that was not quite a word.
The Killer Features You Never Knew You Had
1. Kill a Frozen SSH Session (~.)
You know that thing where your SSH session freezes and you are just staring at a dead terminal? Maybe the network dropped, maybe the server crashed, but your terminal is just... stuck. You cannot type anything. Ctrl+C does nothing. Ctrl+D does nothing.
Most people close the terminal window and open a new one. Like animals.
Instead: press Enter, then ~. (tilde, period). The connection terminates immediately, cleanly, and you are back at your local shell. No closing windows. No waiting for timeouts. No wondering if the session is actually dead or just thinking really hard.
This alone would have saved me approximately 4,000 terminal-closing-and-reopening cycles over the past decade. I try not to think about it.
2. Add Port Forwards Without Reconnecting (~C)
This is the one that genuinely blew my mind. Press Enter, then ~C to open an SSH command line while you are already connected. From there, you can add port forwards on the fly:
ssh> -L 8080:localhost:3000
Forwarding port.
You just set up local port forwarding without disconnecting and reconnecting with -L. In a live session. While your other commands are still running.
Think about how many times you have been SSH’d into a server, realized you need to access a web interface running on port 3000, and had to either open a new terminal with the right flags or disconnect and reconnect. All of that was unnecessary. This whole time.
You can also add remote forwards (-R) and dynamic forwards (-D) the same way. And remove them with -KL, -KR, and -KD.
Hannah, who runs our infrastructure team, nearly fell out of her chair when I showed her this. She had been keeping a text file — a literal text file — of all the port forwards she might need so she could copy-paste the right SSH command when she needed them. That text file is now retired.
3. Background a Session (~& and ~^Z)
Need to do something locally but do not want to kill your SSH session? Press Enter, then ~^Z (tilde, then Ctrl+Z) to suspend the SSH connection. It goes to the background just like any other suspended process. Bring it back with fg.
Alternatively, ~& backgrounds it properly, which is useful when you are waiting for port-forwarded connections to finish.
I used to open new terminal tabs for local work because I did not want to lose my SSH session. Now I just suspend it. It is faster, uses less memory, and my tab bar does not look like it was designed by someone with a hoarding disorder.
4. List Active Forwards (~#)
Ever set up a bunch of port forwards and then forgotten which ones are active? Press Enter, then ~# to list all currently forwarded connections. It shows you local forwards, remote forwards, and dynamic forwards, along with their current state.
This is diagnostic gold when you are troubleshooting why a connection is or is not working.
5. Adjust Logging Verbosity On the Fly (~V/v)
If you need to debug an SSH connection issue — maybe tunnels are not working, maybe authentication is flaky — you can increase the verbosity of SSH logging without reconnecting. Press Enter, then ~v to increase verbosity, or ~V to decrease it.
This is the equivalent of adding -v, -vv, or -vvv to your SSH command, except you do not have to disconnect. You can watch the debug output in real time while reproducing the issue.
Before I knew this existed, I would disconnect, reconnect with -vvv, try to reproduce the problem, and hope the added verbosity did not change the timing enough to make the bug disappear. Which it did. Frequently.
SSH Config Tricks That Save Hours
While we are talking about SSH features most people ignore, let me share some ~/.ssh/config settings that have made my life measurably better:
Connection Multiplexing
Host *
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h-%p
ControlPersist 600
This reuses a single SSH connection for multiple sessions to the same server. The first ssh command opens the connection. Every subsequent one piggybacks on it. No new TCP handshake, no new authentication. Connections are instant.
Make sure to create the sockets directory first: mkdir -p ~/.ssh/sockets
I cannot overstate how much faster this makes working with servers you connect to frequently. Going from a 2-second connection to an instant one does not sound like much, but multiply it by 50 connections a day and suddenly you have saved actual minutes of your life. Minutes you can spend doing something more productive, like reading articles about SSH tricks you should have known twelve years ago.
Keep Connections Alive
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
This sends a keepalive packet every 60 seconds and drops the connection after 3 missed responses. No more frozen sessions because your laptop went to sleep for 30 seconds, or because a NAT gateway decided your connection was idle and silently dropped it.
Combined with the escape character trick for killing truly dead sessions, this eliminates about 95% of the “is my terminal frozen or just slow?” problem.
Jump Hosts Made Easy
Host internal-server
HostName 10.0.1.50
User admin
ProxyJump bastion.example.com
Instead of SSH-ing to a bastion host and then SSH-ing again to the internal server, you can jump through in a single command: ssh internal-server. The ProxyJump directive handles the intermediate hop automatically.
You can chain multiple jumps too: ProxyJump bastion1,bastion2. I have a setup that goes through three jump hosts to reach a particularly paranoid client’s production database, and it feels like a single connection.
Per-Host Configuration
Host prod-*
User deploy
IdentityFile ~/.ssh/prod_key
ForwardAgent no
Host dev-*
User developer
IdentityFile ~/.ssh/dev_key
ForwardAgent yes
Wildcard matching in SSH config lets you set different credentials, keys, and settings for different server groups. Production servers use the deploy key with agent forwarding disabled (for security). Dev servers use a different key with agent forwarding enabled (for convenience).
This is basic stuff, but I still see people typing ssh -i ~/.ssh/specific_key -o ForwardAgent=no user@host by hand every single time. Stop doing that. Life is too short.
The SSHFP Record Nobody Uses
Quick tangent that I think more people should know about: you can publish your server’s SSH host key fingerprint in DNS using an SSHFP record. When a client connects and sees the SSHFP record, it can verify the host key automatically instead of showing you that “The authenticity of host X can’t be established” message that everyone just types “yes” to without reading.
You know who you are. You type “yes” without reading it. Every time. It is fine. We all do it. But SSHFP records mean you do not have to, and the verification actually happens properly.
To generate an SSHFP record: ssh-keygen -r yourdomain.com
Add the output to your DNS zone file, enable VerifyHostKeyDNS yes in your SSH config, and you have got cryptographic host verification backed by DNSSEC. Nobody does this, but everybody should.
One More Thing: SSH Certificates
If you manage more than about five servers, stop using individual SSH keys and start using SSH certificates. The setup takes about an hour. The time savings over the next year will be enormous.
Instead of copying your public key to every server (and then managing revocations when someone leaves the team, which nobody actually does), you set up a Certificate Authority, sign short-lived certificates, and the servers trust anything signed by the CA.
New team member? Sign a certificate. Someone leaves? Do not renew their certificate. It expires automatically. No need to go to every server and remove their key from authorized_keys.
Greg, who manages infrastructure at a company with 200+ servers, told me switching to SSH certificates was “the single best infrastructure decision we made last year.” He used to spend hours onboarding and offboarding engineers. Now it takes minutes.
The Bottom Line
SSH is one of those tools that most of us learn just enough to be functional and then never revisit. We learn ssh user@host, maybe we figure out keys and basic tunneling, and we call it done.
But there is an entire layer of functionality hiding in plain sight — escape characters, live port forwarding, connection multiplexing, SSH certificates, SSHFP records — that can genuinely transform how you work with remote servers.
The escape character menu alone is worth the price of admission. Press Enter, type ~?, and discover what has been there the whole time.
(And if you have known about all of this for years and are reading this with a smug expression, just know that the rest of us do not appreciate your silence. You could have said something. At any point in the last twelve years. Jake.)