Run a Temporary SSH Agent Safely from Your Shell
Typing the same SSH passphrase for the tenth time in an hour is what finally sends most people to ssh-agent. It holds a decrypted private key in memory for a set time, so ssh can use it without asking again on every connection. You will finish with an agent attached to your current shell, one key loaded with a bounded lifetime, and a clean way to shut it all down.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about ten minutes. You need the Debian or Ubuntu openssh-client package, a shell, and an existing private key whose passphrase you know. The examples use the installed OpenSSH client package version 1:9.6p1-3ubuntu13.19 and need no root. Do not use an agent on an untrusted machine, and do not forward it casually to a host you do not control.
1. Check the installed program
Confirm which binary your shell will run and check the package version. Both commands are read-only:
$ command -v ssh-agent
/usr/bin/ssh-agent
$ dpkg-query -W -f='${Package} ${Version}\n' openssh-client
openssh-client 1:9.6p1-3ubuntu13.19
Three forms are worth knowing: eval "$(ssh-agent -s)" for a Bourne-style shell, ssh-agent command for an agent tied to one child process, and ssh-agent -k to stop the agent named by SSH_AGENT_PID. A fresh agent always starts with no identities loaded.
Checkpoint
If command -v finds a wrapper or an unexpected path, stop and work out why before entering a passphrase.
2. Start the agent in this shell
Run this in the shell where you will actually use ssh:
$ eval "$(ssh-agent -s)"
Agent pid 12345
The PID above is an example; yours will differ every time. The command evaluates shell assignments printed by ssh-agent, including SSH_AUTH_SOCK and SSH_AGENT_PID, so every later SSH command in this shell can find the agent through those variables. Open a second terminal and it has none of this: the environment is not copied automatically.
Check both values without exposing a private key:
$ printf 'socket: %s\npid: %s\n' "$SSH_AUTH_SOCK" "$SSH_AGENT_PID"
socket: /tmp/ssh-XXXXXXXXXX/agent.12345
pid: 12345
$ test -S "$SSH_AUTH_SOCK" && echo 'agent socket exists'
agent socket exists
The socket sits under $TMPDIR, or the system temporary directory if that variable is unset, and should be reachable only by your user. Worth knowing: root, and another process running as the same user, can still abuse it.
3. Add one key with an expiry
Name the key explicitly rather than letting anything pick for you:
$ KEY="$HOME/.ssh/id_ed25519"
$ test -r "$KEY" && echo "key is readable"
key is readable
$ ssh-add -t 1h "$KEY"
Enter passphrase for /home/you/.ssh/id_ed25519:
Identity added: /home/you/.ssh/id_ed25519 (you@example)
-t 1h caps this one identity's lifetime at an hour. The agent's own -t flag sets a default for keys added later, and an explicit ssh-add -t overrides that default. Skip both and a key can sit loaded until the agent exits, which is exactly how people end up with a week-old key still live in a login session nobody remembers opening.
Never paste a passphrase into a command line, a script, or a terminal recording. If the key path is wrong, fix the path rather than pointing at a different private key. Adding a key only changes the agent's in-memory state, never the key file itself.
4. Verify what the agent holds
List the public identities the current agent is carrying:
$ ssh-add -l
256 SHA256:REDACTED-FINGERPRINT you@example (ED25519)
Fingerprint and comment are specific to your key. The agent has no identities means the earlier eval did not run in this shell, or the key was never accepted. A message about the connection to the authentication agent failing means check SSH_AUTH_SOCK and rerun test -S "$SSH_AUTH_SOCK".
For a real test, just connect and let SSH try the loaded identity:
$ ssh -o IdentitiesOnly=no [email protected]
[email protected]'s password:
Use your actual account and host in place of the placeholders. A password prompt here does not prove the agent failed: it can just as easily mean the server rejected the offered key, the account is wrong, or the key was never authorised there.
5. Remove the key when you finish
Removing an identity is reversible and only touches memory. This drops the selected key while the agent keeps running:
$ ssh-add -d "$KEY"
Identity removed: /home/you/.ssh/id_ed25519 (you@example)
$ ssh-add -l
The agent has no identities.
ssh-add -D clears every identity the agent holds, which is destructive to that shared state, so do not run it in a session other people are also using unless you mean to strip their keys too. Adding the key back is just step 3 again.
6. Stop the agent and recover from a stale shell
When you are done, stop the agent from step 2:
$ ssh-agent -k
unset SSH_AUTH_SOCK;
unset SSH_AGENT_PID;
echo Agent pid 12345 killed;
This command prints shell commands rather than running them against your current shell, so unlike the earlier eval it leaves your variables in place until you evaluate its output. Finish the cleanup properly:
$ eval "$(ssh-agent -k)"
Agent pid 12345 killed
$ unset KEY
$ test -z "${SSH_AUTH_SOCK:-}" && echo 'agent environment cleared'
agent environment cleared
Close a shell before running cleanup and its agent can outlive it until the socket or process is removed. In a new shell, do not guess a PID and kill it blind: check the process owner and command line first with ps -u "$USER" -o pid=,comm=,args= | grep '[s]sh-agent'. Found an abandoned agent you own? Stop that exact process with normal process tools, and never kill an agent belonging to someone else's session without checking what depends on it.
7. Keep forwarding and provider options deliberate
Agent forwarding lets a remote SSH session use your local agent, but the remote host can request signatures for as long as forwarding stays active. Treat a forwarded agent as a credential handed to that host. Use ssh -A only for a host you trust, only for as long as you need it, and prefer a host-specific SSH config entry you remove afterwards over leaving it on globally.
This build of ssh-agent also supports -O allow-remote-pkcs11 and -O no-restrict-websafe, both of which relax protections around remote provider loading or FIDO signatures. Leave them out of any routine startup command: the default restrictions are what stop forwarded access turning into access to an unrelated PKCS#11 provider or website authentication.
Do not put the agent socket in a shared directory with -a unless you have a deliberate ownership and permission design behind it, and skip -d or -D for normal shell setup since they keep the agent in the foreground and dump diagnostics to standard error. For a single command's worth of scope, this is the safer pattern:
$ ssh-agent ssh-add -l
The agent has no identities.
That child agent exits the moment ssh-add -l exits. It is not useful for a multi-command shell, because its environment never reaches the parent.
Done means
- Socket confirmed.
SSH_AUTH_SOCKpoints to an existing socket owned for this session. - Key loaded correctly. The intended identity appears in
ssh-add -l, with a bounded lifetime where it matters. - No key left the machine. SSH uses the agent without ever copying a private key to the remote host.
- Forwarding is off by default. It only gets switched on for a trusted destination that actually needs it.
- Cleanup done. Loaded identities were removed or the agent stopped, and the shell carries no stale agent variables.