DEV Community

Svyatoslav Pavlov
Svyatoslav Pavlov

Posted on Originally published at termal.in on

ssh-agent and ssh-add, in practice: stop typing your passphrase

You've done the right thing and put a passphrase on your SSH key — and now you're typing it for the fifth time before lunch. The fix has existed for decades: the SSH agent. Unlock the key once, and every connection after that authenticates silently. The catch is that "once" only works if the agent is actually running, your shell can find it, and the key is loaded — three separate things, each with its own way of failing. This is the practical guide: starting the agent on each OS, driving it with ssh-add, making the whole thing automatic, and decoding the two errors that account for nearly all agent trouble.

What the agent is, in one paragraph

ssh-agent is a small background process that holds your decrypted private keys in memory. When a server challenges you, ssh hands the challenge to the agent, the agent signs it with the in-memory key, and only the signature goes back — the key itself never leaves the agent, never touches the wire, and stays encrypted on disk. One passphrase prompt to load the key, then every later connection is served from memory. If you want the full mental model — why it's built as a signing service and what that implies — that's covered in what is the SSH agent?; this post stays hands-on.

Starting the agent, per OS

Linux. On a desktop login you almost certainly have an agent already — either a systemd user service or GNOME Keyring playing the role — with SSH_AUTH_SOCK exported for your whole session. Test with ssh-add -l. If nothing answers (common over a bare SSH login, in containers, or on minimal servers), start one by hand:

eval "$(ssh-agent -s)"
Enter fullscreen mode Exit fullscreen mode

The eval matters. ssh-agent -s only prints the SSH_AUTH_SOCK and SSH_AGENT_PID variables; the eval is what sets them in your current shell so ssh can find the socket. Running ssh-agent bare and wondering why nothing changed is the single most common way to "start" an agent that no tool can see.

macOS. launchd runs an agent for you from login — there is nothing to start. The macOS-specific win is the Keychain integration below.

Windows. Modern Windows ships an OpenSSH Authentication Agent service, but it's not running by default. Enable it once, from an elevated PowerShell:

Set-Service ssh-agent -StartupType Automatic
Start-Service ssh-agent
Enter fullscreen mode Exit fullscreen mode

After that, ssh-add works in any terminal, and the agent survives reboots.

Driving it with ssh-add

Load, inspect, and clear keys:

ssh-add                          # load the default keys (id_ed25519, id_rsa, …)
ssh-add ~/.ssh/work_ed25519      # load a specific key
ssh-add -l                       # list fingerprints of loaded keys
ssh-add -L                       # print the full public keys
ssh-add -d ~/.ssh/work_ed25519   # remove one key
ssh-add -D                       # remove all keys
Enter fullscreen mode Exit fullscreen mode

ssh-add -l is the first diagnostic for any auth problem: if the key you expect isn't in that list, the agent can't sign with it, whatever else looks right.

Two flags are worth making habits:

  • -t sets a lifetime. ssh-add -t 3600 ~/.ssh/id_ed25519 loads the key for one hour; after that the agent forgets it and the next use re-prompts. A key that sits unlocked in memory for a three-week uptime is a key usable long after you stopped thinking about it.
  • -c requires confirmation. Every signing request pops a local prompt before the agent answers. Slightly annoying, exactly right for high-value keys.

Make it automatic: AddKeysToAgent

The manual ssh-add ritual disappears with one line in ~/.ssh/config:

Host *
    AddKeysToAgent yes
Enter fullscreen mode Exit fullscreen mode

Now the first ssh that needs a key prompts for the passphrase once and loads the key into the agent as a side effect. No separate command to remember — the prompt simply stops recurring. You can set it to a lifetime too (AddKeysToAgent 1h) to get the -t behaviour without the flag.

macOS: survive reboots with the Keychain. By default the agent forgets keys when it restarts. macOS can store the passphrase in your login keychain so keys reload without retyping:

ssh-add --apple-use-keychain ~/.ssh/id_ed25519
Enter fullscreen mode Exit fullscreen mode

and in ~/.ssh/config:

Host *
    AddKeysToAgent yes
    UseKeychain yes
Enter fullscreen mode Exit fullscreen mode

After that, the passphrase question is answered by the Keychain at login and you never see it again — while the key file on disk stays encrypted.

The two errors everyone hits

Could not open a connection to your authentication agentssh-add can't find an agent. Either none is running, or one is running but this shell doesn't have SSH_AUTH_SOCK set. The fix is the per-OS start above: the eval "$(ssh-agent -s)" line on Linux (check first whether your desktop session already provides one — starting a second agent per terminal just scatters loaded keys across processes), the service start on Windows. You'll also meet this in cron jobs and CI, where no login session ever exported the variable.

The agent has no identities. — the opposite problem: the agent is fine, but nothing is loaded. ssh-add your key. If it was loaded and vanished, a -t lifetime expired or the agent restarted — which is precisely what AddKeysToAgent yes and the macOS Keychain are for.

And the third case: the agent looks perfect — ssh-add -l shows the key — but the server still says Permission denied (publickey). That's no longer an agent problem; work through the publickey checklist — wrong user, wrong key offered, authorized_keys permissions.

An unlocked agent is a live credential

The agent never leaks the key — but it signs for whoever can reach its socket, and it doesn't ask who's asking. On your own machine that means any process running as your user can request signatures: that's the deal you accept for the convenience, and it's why agent hygiene is worth the small effort.

  • Give keys a lifetime (-t, or a lifetime on AddKeysToAgent) so an idle agent goes cold on its own.
  • Lock the agent when stepping away: ssh-add -x locks it behind a password, ssh-add -X unlocks; ssh-add -D simply drops everything.
  • Use -c for the keys that reach production.
  • Don't forward the agent by default. ssh -A exposes live use of your keys on the remote host — anyone with root there can sign as you for the length of your session. That one deserves its own read: agent forwarding is convenient and dangerous.

How Termalin handles this

Termalin builds this whole workflow in, with the sharp edges filed down. Its key agent unlocks your keys once and signs on your behalf — no OS service to enable, no eval line, no per-shell socket to lose. Passphrase caching comes with a re-lock timeout by default, which is the ssh-add -t habit enforced for you rather than remembered by you. And because it speaks the standard ssh-agent protocol, git and your existing CLI tools sign through it unchanged — it replaces the ritual, not your toolchain.


Termalin is a free, cross-platform SSH client whose built-in agent unlocks your keys once and re-locks on a timer — download it, or read how it handles your keys safely.

Top comments (0)