If your SSH key has a passphrase (it should), typing it for every connection gets old fast. ssh-agent keeps your unlocked keys in memory, so you enter the passphrase once per session. Agent forwarding lets a server you’re logged into use your local keys, for example to git pull from a private repository, without copying your private key to the server.
ssh-agent basics
Most desktop environments and macOS start an agent automatically. Check:
echo "$SSH_AUTH_SOCK"
ssh-add -l # list loaded keys ("The agent has no identities" = empty)
Start one manually if needed (in a plain shell or on a server):
eval "$(ssh-agent -s)"
Add your key:
ssh-add ~/.ssh/id_ed25519 # asks for the passphrase once
ssh-add -t 4h ~/.ssh/id_ed25519 # forget it after 4 hours
ssh-add -l # verify
ssh-add -D # remove all keys from the agent
Automatic loading
In ~/.ssh/config on your computer:
Host *
AddKeysToAgent yes
IdentityFile ~/.ssh/id_ed25519
The first connection asks for the passphrase and adds the key to the agent. Later connections don’t ask. On macOS, add UseKeychain yes to store the passphrase in the Keychain.
Windows: enable the “OpenSSH Authentication Agent” service, then use ssh-add in PowerShell.
See SSH keys with ssh-keygen and SSH config file.
Agent forwarding
Scenario: you SSH into your web server and need to git pull from a private GitHub repository. The deploy key isn’t on the server, it’s on your laptop. With forwarding:
ssh -A deploy@web1
# on web1:
ssh-add -l # shows YOUR laptop's keys
git pull # authenticates to GitHub with your laptop key
Or per host in ~/.ssh/config:
Host web1
HostName 203.0.113.10
User deploy
ForwardAgent yes
The private key never leaves your computer. The server just asks your agent to sign authentication requests through the SSH connection.
The server’s sshd_config must allow it with AllowAgentForwarding yes, which is the default.
The risk: root on the server can use your agent
While you’re connected with forwarding, anyone with root on that server, or access to your user there, can use your agent socket to authenticate as you to any other server or service your keys open. They can’t copy the key, but they can use it while you’re connected.
Guidelines:
- Never enable
ForwardAgent yesforHost *. Enable it only for specific, trusted servers. - Don’t forward to shared or untrusted machines.
- Use
ssh-add -c(confirm). The agent asks for confirmation on your desktop for each use (needsssh-askpass). - Prefer the alternatives below when they fit.
Safer alternatives
Jumping through a bastion host? Use ProxyJump instead of forwarding:
ssh -J bastion.example.com app-server
The connection to app-server is tunnelled through the bastion, but authentication happens from your laptop. The bastion never gets access to your agent. See SSH jump host with ProxyJump.
Deploying from a server? Use a deploy key on the server. Create a dedicated key on the server and add it as a read-only deploy key to that one repository:
ssh-keygen -t ed25519 -f ~/.ssh/deploy_myrepo -N ""
Add the public key in the repository’s settings under Deploy keys, and map it in ~/.ssh/config:
Host github-myrepo
HostName github.com
User git
IdentityFile ~/.ssh/deploy_myrepo
Then clone with git clone git@github-myrepo:org/myrepo.git. If the server is compromised, only read access to one repository is exposed. See Git SSH keys.
CI/CD pipelines should use their own secrets and deploy keys, not a human’s forwarded agent. See GitHub Actions deploy.
Troubleshooting
Could not open a connection to your authentication agent — no agent is running in this shell. Run eval "$(ssh-agent -s)".
Forwarding doesn’t work (ssh-add -l on the server says no agent) — check ForwardAgent yes or -A, that the server allows AllowAgentForwarding, and that sudo isn’t dropping SSH_AUTH_SOCK. With sudo -E, or an env_keep += "SSH_AUTH_SOCK" sudoers rule, the variable is kept, but root also needs permission on the socket. That’s another reason to prefer deploy keys.
Inside tmux or screen, the agent stops working after reconnecting — the socket path changed. Use a stable symlink (~/.ssh/ssh_auth_sock) updated in ~/.ssh/rc.
Quick reference
| Task | Command |
|---|---|
| Start agent | eval "$(ssh-agent -s)" |
| Add key | ssh-add ~/.ssh/id_ed25519 |
| Add with timeout | ssh-add -t 4h key |
| List / remove keys | ssh-add -l / ssh-add -D |
| Forward once | ssh -A host |
| Forward per host | ForwardAgent yes in ~/.ssh/config |
| Safer hop | ssh -J bastion target |
Related: SSH hardening and SSH tunnels.