SSH Config: Multiple Keys for Multiple Hosts (Per-Host SSH Keys)

SSH config file mapping multiple SSH keys to multiple hosts

If you juggle more than one SSH key — a personal GitHub account and a work one, a few servers, a deploy key — you’ve probably been retyping -i ~/.ssh/whatever on every command, or worse, hitting “Too many authentication failures” because SSH is throwing every key you own at the server until it gets locked out. The fix is a single file: ~/.ssh/config. This guide shows you how to map multiple SSH keys to multiple hosts cleanly, including the tricky case of two GitHub or Bitbucket accounts on one machine.

Why you need ~/.ssh/config

By default, when you run ssh user@host, the SSH client offers every private key it can find (and every key loaded in your agent) one after another. Two problems follow:

  • Lockouts. Most servers cap authentication attempts at around six. If your agent holds more keys than that, the right key may never get tried — SSH gives up first with “Too many authentication failures.”
  • Wrong identity. With two GitHub accounts, the first key offered wins, so you push to the wrong account or get “permission denied.”

A config file solves both by telling SSH exactly which key to use for which host — and nothing else.

The basic structure

Create (or edit) ~/.ssh/config and set its permissions so SSH trusts it:

touch ~/.ssh/config
chmod 600 ~/.ssh/config

The file is a list of Host blocks. Each block defines an alias and the settings SSH should use when you connect to it:

Host my-vps
  HostName 203.0.113.10
  User deploy
  Port 22
  IdentityFile ~/.ssh/vps_ed25519
  IdentitiesOnly yes

Now ssh my-vps expands to “connect to 203.0.113.10 as deploy on port 22 using only the vps_ed25519 key.” No flags, no guessing.

The two directives that matter most

DirectiveWhat it does
IdentityFileThe private key to use for this host.
IdentitiesOnly yesThe key to avoiding lockouts. Tells SSH to offer only the IdentityFile above and ignore every other key in the agent. Always set this when you have multiple keys.

Multiple keys for multiple servers

Just add one block per server, each pointing at its own key:

Host prod
  HostName 203.0.113.10
  User deploy
  IdentityFile ~/.ssh/prod_ed25519
  IdentitiesOnly yes

Host staging
  HostName 203.0.113.20
  User deploy
  IdentityFile ~/.ssh/staging_ed25519
  IdentitiesOnly yes

# Shared hosting on a non-standard port
Host hostinger
  HostName 203.0.113.30
  User u123456789
  Port 65002
  IdentityFile ~/.ssh/hostinger_ed25519
  IdentitiesOnly yes

Then ssh prod, ssh staging, or ssh hostinger each use the correct key, user, and port automatically. The same aliases work with scp and rsync too, because they read the same config.

Two GitHub (or Bitbucket) accounts on one machine

This is the classic case. Both accounts live at the same real host (github.com), so you can’t tell them apart by hostname alone. The trick is to invent a fake Host alias for each account and map it back to the real host:

Host github-personal
  HostName github.com
  User git
  IdentityFile ~/.ssh/personal_ed25519
  IdentitiesOnly yes

Host github-work
  HostName github.com
  User git
  IdentityFile ~/.ssh/work_ed25519
  IdentitiesOnly yes

Now you choose the account by which alias you use in the remote URL. For a work repo, set the remote like this:

# Clone using the alias instead of github.com
git clone git@github-work:acme/internal-app.git

# Or fix an existing repo's remote
git remote set-url origin git@github-work:acme/internal-app.git

Git connects to github-work, SSH rewrites that to github.com with the work key, and GitHub authenticates you as the right account. Verify each alias independently:

ssh -T git@github-personal
ssh -T git@github-work

Helpful global defaults

A Host * block at the bottom of the file applies sensible defaults to every connection (specific blocks above it still win):

Host *
  AddKeysToAgent yes
  ServerAliveInterval 60
  ServerAliveCountMax 3
  • AddKeysToAgent yes — loads a key into the agent the first time you use it, so you only enter its passphrase once.
  • ServerAliveInterval / ServerAliveCountMax — send a keep-alive every 60 seconds and drop the connection after three misses, preventing “broken pipe” timeouts on idle sessions.
  • On macOS, add UseKeychain yes inside this block to pull passphrases from the Keychain.

Troubleshooting

  • “Too many authentication failures.” You’re missing IdentitiesOnly yes on the host block, so the agent is offering every key. Add it.
  • Wrong GitHub account is used. Your repo’s remote still points at github.com instead of your alias. Run git remote -v and update it with git remote set-url.
  • Config seems ignored. Permissions are wrong (chmod 600 ~/.ssh/config), or the file is in the wrong place — it must be ~/.ssh/config. Debug with ssh -v my-host to see which config and key are loaded.
  • Order matters. SSH applies the first matching value for each setting, so put specific Host blocks above broad Host * wildcards.

New to keys altogether? Start with our guide on how to generate an SSH key, and see copying files with SCP — both honor the aliases you define here.

Frequently asked questions

How do I use a different SSH key for each host?

Add a Host block per server in ~/.ssh/config with its own IdentityFile and IdentitiesOnly yes. Then connect with the alias, e.g. ssh prod, and SSH uses that host’s key automatically.

How do I use two GitHub accounts with different SSH keys?

Create two Host aliases (e.g. github-personal and github-work) that both set HostName github.com but different IdentityFile values. Then set each repo’s remote to use the matching alias, e.g. git@github-work:org/repo.git.

What does IdentitiesOnly yes do?

It forces SSH to offer only the key named in that host’s IdentityFile, instead of every key in your agent. This prevents the “Too many authentication failures” lockout when you have several keys.

Previous