TechEarl

Use Multiple SSH Keys with ~/.ssh/config

Run separate SSH keys for work, personal, and GitHub by binding each to its host in ~/.ssh/config with IdentityFile and IdentitiesOnly, so the right key is always offered.

Ishan Karunaratne⏱️ 4 min readUpdated
Share thisCopied
Bind separate SSH keys to separate hosts in ~/.ssh/config with IdentityFile and IdentitiesOnly so the correct key is offered every time.

To use multiple SSH keys, bind each key to its host in ~/.ssh/config with an IdentityFile line plus IdentitiesOnly yes, so SSH offers only the right key per host. If you keep separate SSH keys (work versus personal, prod versus staging, one GitHub account versus another), the problem is making SSH pick the right one automatically. The answer is ~/.ssh/config: bind each key to the host that should use it.

Why you get "too many authentication failures"

By default SSH offers every key it can find, in order, until one works or the server cuts you off (MaxAuthTries, usually 6). With several keys loaded you can exhaust that limit before the correct key is tried, and the server returns Too many authentication failures. The fix is to tell SSH exactly which key goes with which host, and to offer only that one.

A config that maps keys to hosts

code
# ~/.ssh/config

Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519_personal
    IdentitiesOnly yes

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

Host prod
    HostName prod.example.com
    User deploy
    IdentityFile ~/.ssh/id_ed25519_prod
    IdentitiesOnly yes

IdentitiesOnly yes is the important line: it stops SSH from offering any key except the listed IdentityFile, which is what prevents the "too many failures" cutoff.

Two GitHub accounts on one machine

This is the classic case. GitHub identifies you by the key, not the URL, so you cannot use git@github.com for both. Use a host alias for the second account (the work-git block above), then point the repo at the alias:

bash
git clone git@work-git:company/repo.git
# or change an existing repo's remote:
git remote set-url origin git@work-git:company/repo.git

Personal repos keep using git@github.com:...; work repos use git@work-git:.... Each resolves to github.com but offers a different key.

Test which key a host will use

bash
ssh -T git@github.com      # personal account
ssh -T git@work-git        # work account

GitHub answers Hi USERNAME! with the account the offered key belongs to, so you can confirm each alias maps to the right identity.

FAQ

See also

Sources

Authoritative references this article was fact-checked against.

TagsSSHssh-configIdentityFileGitHubLinuxDevOps

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Software Systems Architect · Senior Software Engineer · Engineering Leadership

Software systems architect and senior software engineer with more than two decades designing, building, and running production software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Now a CTO, though what I write here is drawn from the full arc of that work, across architecture, engineering, and operations, not any single job.

Keep reading

Related posts

Search multiple patterns with grep: grep -e 'A' -e 'B', grep -E 'A|B' alternation, and grep -f patterns.txt. Covers -F fixed strings, AND logic with chained greps and PCRE lookahead, and BSD vs GNU differences on macOS.

How to Search Multiple Patterns with grep

grep can OR several patterns three ways: -e per pattern, -E with alternation, or -f reading the list from a file. The one-liner is grep -E 'ERROR|WARN|FATAL' file. Here is when to pick each, how -F speeds up literal multi-pattern search, why grep has no single-pass AND, and the BSD vs GNU differences that bite on macOS.

How to set up push-to-deploy with GitHub Actions: a CI/CD workflow that builds and deploys on every push to main.

Push-to-Deploy with GitHub Actions

A beginner-friendly intro to CI/CD with GitHub Actions: a real workflow YAML that builds and deploys on every push to main, plus how to handle secrets safely.

Wire ElasticPress to WP_Query so WordPress queries hit Elasticsearch instead of MySQL. Install, indexable post types, ep_integrate, wp-cli index, faceted aggregations, and when ES actually beats MySQL FULLTEXT.

How to Use ElasticPress with WP_Query

Wire ElasticPress to WP_Query so WordPress queries hit Elasticsearch instead of MySQL. Covers installation, indexable post types, ep_integrate, the wp-cli index command, faceted search with aggregations, and when ES actually beats MySQL FULLTEXT.