Cheat Sheet

SSH Commands

ssh is the OpenSSH client that ships with Linux, macOS, and Windows 10 and later. This sheet covers connecting, running remote commands, copying files, keys, the config file, tunnels, and the flags you reach for when a connection misbehaves.

Last updated September 11, 2026

Connecting

Port 22 is the default. Every option below can also live in the config file so you only type .

CommandWhat it does
Log in as user on host (a name or an IP)
Log in with your local username
Non-standard port (lowercase p; scp and sftp use uppercase P)
Use a specific private key
Username as a flag instead of user@host
Go through a jump host (bastion) first
Jump host with its own user and port
Cloud instance: the you downloaded and the image's default user
Raspberry Pi on the same network, by mDNS name
Send a keepalive every 60 seconds so an idle session is not dropped
Accept a never-seen host key without a prompt, still refuse a changed one
Give up after 5 seconds instead of the system default
Compress traffic, useful on slow links
Force IPv4 ( forces IPv6)
Scripted password login (separate package; the password lands in history, use a key instead)
Print the client version
Log out (Ctrl+D on an empty prompt does the same)
Kill a hung session; type it at the start of a line ( lists the other escapes)

If the connection is refused or hangs, check the port from outside with the SSH port checker, then see Connection refused or Could not resolve hostname.

Syntax and Flags

Options go before the host. Anything after the host is treated as the command to run on the far end, so sends to the remote shell instead of turning on verbose output.

ssh [options] [user@]host [command]
FlagWhat it does
Port on the server (scp and sftp spell it )
Private key to offer
Username, when you do not write
Jump through a bastion first
Any setting, same names as the config file
Read a different config file
, , Verbose; repeat for more detail
Quiet: suppress warnings and banners
Force a terminal, for sudo and editors ( forbids one)
Do not run anything, just hold the connection open
Drop to the background once authenticated
Take stdin from so ssh does not eat your input
, , Local, remote, and SOCKS forwarding
Forward your agent to the remote host
, X11 forwarding, untrusted and trusted
Compress the connection
, Force IPv4 or IPv6
Print the effective config for a host and exit
List what this build supports (, )
Print the version

Short flags stack, so is the same as . Every name also works as a plain line in , which is where it belongs once you type it twice.

Remote Commands

CommandWhat it does
Run one command and disconnect
Several commands, quoted as one string
Force a terminal so sudo can ask for a password
Run a local script on the remote host
Save remote output to a local file
Stream a log until Ctrl+C
In double quotes, escape so the remote shell expands it; single quotes need nothing
Start a job that keeps running after you disconnect
Run in the background without ssh grabbing your terminal's input
Never prompt; fail instead (for cron and scripts)
Pass a local variable through (the server needs )
After ssh returns: the remote command's exit code, or 255 if ssh itself failed

For anything longer than one line, pipe a heredoc into a remote shell. Quoting the marker as stops your local shell touching the body:

ssh user@host 'bash -s' <<'EOF'
set -euo pipefail
cd /var/www/app
git pull --ff-only
sudo systemctl reload nginx
EOF

Copying Files

scp and sftp use the same keys, ports, and config aliases as ssh. Remote paths are written .

CommandWhat it does
Upload a file
Download a file to the current directory
Copy a directory
Non-standard port (uppercase P)
Use a specific key
Preserve timestamps and permissions
Copy between two servers through your machine
Limit bandwidth to 8000 Kbit/s
Config alias in place of user@host
Interactive session: , , , , ,
sftp on a non-standard port (uppercase P again)
Resumable sync for big trees; see the rsync cheat sheet
rsync over a non-standard port

Keys

CommandWhat it does
Generate a key pair at (the comment is just a label)
RSA key for old servers that reject ed25519
Key at a chosen path with no passphrase (automation)
Append your public key to the server's
Specific key and port
Manual ssh-copy-id where it is not installed
Print the public key from a private key
Change or remove the passphrase
Show the fingerprint
Permissions ssh insists on; a world-readable key is ignored
Cloud keys work as-is once locked down

Generate a key in the browser with the SSH key generator, check a key that refuses to work with the SSH key validator, and for PuTTY convert it with the PEM to PPK converter. If the server still says Permission denied (publickey), it is almost always permissions or the wrong key being offered.

Config File

turns a long command into . It needs . Build one with the SSH config generator.

Host prod
    HostName 203.0.113.10
    User deploy
    Port 2222
    IdentityFile ~/.ssh/prod_ed25519
    IdentitiesOnly yes
    ProxyJump bastion

Host bastion
    HostName bastion.example.com
    User admin

Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3
    AddKeysToAgent yes
DirectiveWhat it does
The alias you type after ; applies to every host
Real address behind the alias
Username
Port
Key to offer
Offer only that key; fixes Too many authentication failures
Jump host, same as
Keepalive; fixes idle drops and Broken pipe
Give up after 3 missed keepalives
Agent forwarding for this host, same as
A tunnel that opens every time you connect
Load a key into the agent the first time it is used
Trust new hosts on first use, still refuse changed keys
Split the file (goes at the top)
Print the settings that apply to a host after all matching blocks merge
Use a different config file

Port Forwarding

Syntax is , where the destination is named from the SSH server's point of view, so means the server itself.

CommandWhat it does
Local: your reaches port 80 on host
Local: reach a database that only host can see
Remote: port 9000 on host reaches port 3000 on your machine
SOCKS proxy on local port 1080; point a browser or at it
Tunnel only, no shell
Tunnel in the background
Let other machines on your network use the local forward
Several tunnels, repeat the flag
Stop background tunnels
Close a shared master connection when is on

For to accept connections from outside the server, must be set in the server's . Confirm the far end is actually listening with the SSH port checker before you blame the tunnel.

Agent

The agent holds decrypted keys so you type the passphrase once per login.

CommandWhat it does
Start an agent in this shell
Load the default keys, prompting for passphrases
Load a specific key
List loaded keys ( prints the public keys)
Unload one key ( unloads all)
Load a key that expires after an hour
macOS: remember the passphrase in Keychain
Forward the agent so the remote host can use your keys, for on a server
Windows PowerShell (as admin): turn on the built-in agent

Known Hosts

CommandWhat it does
Remove a host's old key after a reinstall; fixes Host key verification failed
Same for a non-standard port
Check whether a host is in known_hosts
Pre-trust a host in scripts (compare the fingerprint first)
On the server: print its fingerprint to compare against the warning
Skip the check entirely; throwaway lab machines only
Do not record the host at all (pair with the line above)

Windows

Windows 10 1809 and later ship the same OpenSSH client, so every command above works unchanged in cmd, PowerShell, and Windows Terminal. What differs is installing it, where it looks for config, and how you lock down a key file.

CommandWhat it does
PowerShell: is the client installed at all
Install it (admin PowerShell), then open a new terminal
Which you are actually running; Git Bash and WSL each ship their own
Where the Windows client reads config, same syntax as on Linux
PowerShell way to write a key path
Windows stand-in for on a downloaded key
Use the WSL client and its separate from PowerShell

PowerShell and Git Bash keep separate directories, so a key generated in one is invisible to the other. files from PuTTY do not work with this client at all; convert them with the PPK to PEM converter or use the PuTTY commands sheet instead.

X11 Forwarding

CommandWhat it does
Forward X11 so GUI programs on the server open on your screen
Trusted X11 with fewer restrictions; try it when gives errors
Quick test

The server needs in and the package. macOS needs XQuartz, Windows needs VcXsrv or the PuTTY setup in Cannot open display.

Debugging

CommandWhat it does
Show the handshake, which keys are offered, and where it stops
Maximum detail
Print the effective config for a host
Test a key against GitHub without asking for a shell
Stop the agent from offering every key it holds
List supported key types (, for the others)
Talk to an old server that only offers ssh-rsa
Is the port open at all (or use the SSH port checker)
On the server: watch the login log ( on RHEL and Fedora)
On the server: check syntax before restarting
On the server: apply config changes ( on RHEL and Fedora)
ErrorFix
ssh permission denied publickey
ssh connection refused
ssh host key verification failed
or ssh broken pipe
ssh too many authentication failures
ssh could not resolve hostname

Exit Codes

after ssh returns tells you whether ssh failed or your remote command did. In a script, is the cheapest reachability check: 0 means the login works.

CodeWhat it means
The remote command ran and succeeded
to Passed straight through from the remote command; ssh worked fine
The remote shell could not find the command you asked for
The remote command was killed by signal n ( is Ctrl+C, is a kill or the OOM killer)
ssh itself failed: DNS, refused, timed out, host key, or authentication

is the only ambiguous one, because a remote command is allowed to return it too. If you get 255 and the command definitely ran, rerun with and check whether the handshake completed before blaming the connection.

Gotchas

  • ssh takes for the port, scp and sftp take . Lowercase on scp means preserve timestamps, and the copy quietly goes to port 22.
  • There is no password flag. If a script needs one, that is , and the better answer is a key plus .
  • A private key readable by anyone else is silently skipped. wants 700, keys and want 600, and the home directory must not be group-writable.
  • Single-quote remote commands. In double quotes your local shell expands and before ssh sends anything.
  • Closing the terminal kills whatever the session was running. Start long jobs inside tmux or under .
  • A background tunnel started with outlives the terminal. finds it when a port is unexpectedly busy.
  • On Windows, in PowerShell is OpenSSH and reads , not PuTTY's saved sessions. See Windows for the install check and the problem.
  • Options belong before the host. does not change the port, it passes to the remote shell and connects on 22.

SSH FAQ

Can I pass a username and password in one ssh command?

Not with ssh itself. There is no password flag, on purpose: ssh reads the password from the terminal so it never lands in shell history or the process list. The username goes in the command as ssh user@host or ssh -l user host. If a script absolutely must supply a password, install sshpass and run sshpass -p 'secret' ssh user@host, or better, sshpass -f pwfile ssh user@host. The real fix is a key: ssh-keygen -t ed25519, then ssh-copy-id user@host, and the password prompt goes away for good.

Why do I get ssh: command not found?

The client is not installed, or it is not on your PATH. On Windows 10 and 11 it is an optional feature: run Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0 in an admin PowerShell, then open a fresh terminal so PATH is re-read. On Debian and Ubuntu it is apt install openssh-client, on Fedora and RHEL dnf install openssh-clients with the s, and on Arch pacman -S openssh. macOS always ships it, so a missing ssh there points at something your ~/.zshrc did to PATH rather than a missing package. Run which -a ssh, or where.exe ssh on Windows, to see which copy you are getting: Git Bash and WSL each carry their own, with their own ~/.ssh directory.

Why is my ssh command not working?

Read the last line before it gives up, because each failure has a different cause and they are not interchangeable. Connection refused means you reached the machine and nothing was listening on that port. A hang with no message at all is usually a firewall dropping packets, so check the port from outside instead of retrying. Permission denied (publickey) means the network is fine and the server turned your key down. Could not resolve hostname is DNS and never SSH. Run ssh -v and read the last few lines: the step it prints before stopping names the layer that broke. echo $? right after settles it, since 255 means ssh itself failed and any other code came back from the remote command.

How do I remove a host from known_hosts?

ssh-keygen -R hostname deletes every entry for that name or IP from ~/.ssh/known_hosts and keeps a backup as known_hosts.old. Use the same spelling you connect with; a host known as both a name and an IP needs two runs, and a non-standard port is written as ssh-keygen -R '[hostname]:2222'. You need this after a server is reinstalled or replaced, because its host key changes and ssh refuses to connect with Host key verification failed. If nothing was reinstalled and the key still changed, ask whoever runs the server before you delete anything.

Is ssh command line only?

The OpenSSH ssh binary is, but the protocol is not. VS Code's Remote-SSH extension opens a folder on a server and reads your ~/.ssh/config, so an alias you set up for the command line works there with no extra setup. Most file managers speak sftp:// for drag-and-drop copies over the same connection scp uses. On Windows, PuTTY gives you a GUI for the same protocol. The one thing that does not carry over is PuTTY's own storage: it keeps sessions in the Windows registry rather than ~/.ssh/config, and it wants .ppk keys, so an OpenSSH key has to be converted first.

Related cheat sheets