SSH "Too many authentication failures" before the password prompt: agent keys and IdentitiesOnly
An engineer with nine keys in ssh-agent could not log in to a new server: the connection closed with Too many authentication failures before the right key was tried. How OpenSSH offers keys, why MaxAuthTries cuts it off, and a per-host config that fixes it and is safer.
A new team member could log in to every server except a freshly provisioned bastion host. Others on the team could log in fine with the same instructions. Their attempt ended almost immediately:
$ ssh deploy@bastion.example.com
Received disconnect from 203.0.113.40 port 22:2: Too many authentication failures
Disconnected from 203.0.113.40 port 22
No password prompt, no "permission denied". The server simply closed the connection.
Verbose output tells the story
ssh -v deploy@bastion.example.com 2>&1 | grep -E 'Offering|Authentications|Server accepts|disconnect'
debug1: Authentications that can continue: publickey
debug1: Offering public key: /home/maya/.ssh/id_ed25519 ED25519 SHA256:k1Q... agent
debug1: Authentications that can continue: publickey
debug1: Offering public key: maya@work-gitlab ED25519 SHA256:7Rf... agent
debug1: Authentications that can continue: publickey
debug1: Offering public key: maya@personal-github ED25519 SHA256:aZ0... agent
Received disconnect from 203.0.113.40 port 22:2: Too many authentication failures
The client offered three keys from the agent, none of them the one authorised for this server, and then the server disconnected. The authorised key was the ninth in the agent.
ssh-add -l | wc -l
# 9
Checking the server side
The bastion was built from a hardened image with this in /etc/ssh/sshd_config.d/10-hardening.conf:
MaxAuthTries 3
Other servers used the OpenSSH default of 6. With MaxAuthTries 3, the server disconnects after three
failed attempts on one connection (failures start being logged at half that value). A client offering
many wrong keys runs out of attempts long before reaching the right one. On the default of 6 the engineer would
also have failed, just later, which is why the problem only appeared once a server was stricter. In the
server log:
sshd[4410]: error: maximum authentication attempts exceeded for deploy from 198.51.100.77 port 50122 ssh2 [preauth]
sshd[4410]: Disconnecting authenticating user deploy 198.51.100.77 port 50122: Too many authentication failures [preauth]
What we ruled out
- Wrong key on the server. The intended public key was present in
~deploy/.ssh/authorized_keys, and logging in with-i ~/.ssh/bastion_ed25519 -o IdentitiesOnly=yesworked first time. - File permissions.
authorized_keyswas600and owned bydeploy; sshd'sStrictModeswould have logged a different error. - Network filtering or fail2ban. The connection reached sshd every time; no bans were recorded.
Root cause
The engineer's ssh-agent held nine keys. Without explicit configuration, OpenSSH offers every key in the
agent, in order, and each rejected key counts as an authentication attempt. The bastion's stricter
MaxAuthTries 3 made the server disconnect long before the ninth key. Other engineers had only one or
two keys loaded, so they never noticed.
How the client chooses keys
For public key authentication, the OpenSSH client tries, in order:
- keys held by ssh-agent (all of them, unless restricted);
- keys listed with
IdentityFilein~/.ssh/configor-ion the command line; - default key files such as
~/.ssh/id_ed25519and~/.ssh/id_rsa.
IdentitiesOnly yes changes this: the client only offers the identities configured for that host
(IdentityFile or -i), even if the agent holds more. The agent can still sign with the configured key,
so passphrase caching still works.
Why the server counts keys
MaxAuthTries limits authentication attempts per connection. It slows down guessing and limits how many
keys a client can probe. Offering a public key the server does not accept counts as an attempt.
Hardening guides often lower it from 6 to 3 or 4, which is reasonable, but it exposes this client-side
behaviour.
There is also a privacy angle
Offering every key to every server tells each server the public keys you hold. A malicious or compromised server can use that to link your identities, for example to match your work key with a key published on a public code hosting profile. Restricting keys per host avoids that leak.
Environment
| Component | Version / value |
|---|---|
| Client | OpenSSH 9.6p1 on Ubuntu 24.04, ssh-agent with 9 keys |
| Server | OpenSSH 9.2p1 on Debian 12 |
| Server setting | MaxAuthTries 3, PasswordAuthentication no |
| Key used for bastion | ~/.ssh/bastion_ed25519 |
Per-host client configuration
The fix belongs on the client: tell SSH which key to use for which host.
# ~/.ssh/config
Host bastion bastion.example.com
HostName bastion.example.com
User deploy
IdentityFile ~/.ssh/bastion_ed25519
IdentitiesOnly yes
Host *.internal.example.com
ProxyJump bastion
User deploy
IdentityFile ~/.ssh/bastion_ed25519
IdentitiesOnly yes
Host github.com
IdentityFile ~/.ssh/github_ed25519
IdentitiesOnly yes
Host *
AddKeysToAgent yes
IdentitiesOnly yes
The final Host * block makes IdentitiesOnly the default, so a forgotten host entry fails clearly
instead of spraying every key. ssh applies the first value it finds for each option, so specific host
blocks must come before Host *.
ssh -v bastion 2>&1 | grep -E 'Offering|Authenticated'
debug1: Offering public key: /home/maya/.ssh/bastion_ed25519 ED25519 SHA256:Mm2... explicit agent
debug1: Authenticated to bastion.example.com ([203.0.113.40]:22) using "publickey".
Keep the agent small and short-lived
ssh-add -D # remove all keys from the agent
ssh-add -t 8h ~/.ssh/bastion_ed25519 # add with an 8-hour lifetime
ssh-add -c ~/.ssh/prod_ed25519 # require confirmation for each use
A lifetime limits the window in which malware on the laptop can use the agent, and -c makes each use
of a sensitive key visible.
Do not "fix" it on the server
Raising MaxAuthTries back to a high value would make the symptom go away for everyone and weaken the
server against probing. The server setting was correct; the client was misconfigured.
Alternatives and trade-offs
- One key per purpose with hardware backing.
ed25519-skkeys on a FIDO2 security key keep the private key off the laptop entirely, at the cost of touching the key on each login. - SSH certificates signed by an internal CA, with short validity. Clients present one certificate instead of many keys, and servers trust the CA. Excellent at scale, more setup.
- A session manager or zero trust gateway instead of a public bastion, which removes inbound SSH from the internet.
How to test the fix
ssh -G bastion | grep -E '^(identitiesonly|identityfile|user) '
# identitiesonly yes
# identityfile ~/.ssh/bastion_ed25519
# user deploy
ssh -G prints the configuration SSH would use for a host without connecting, which is the quickest way
to check which blocks apply.
Confirming
The engineer connected on the first key offered. The server log showed a single accepted publickey
attempt per login. We added the ~/.ssh/config snippet to the onboarding guide and asked everyone to
run ssh -G against the bastion to confirm.
Regression guard
- The onboarding script installs the shared
~/.ssh/config.d/company.confand anIncludeline for it. - New servers keep
MaxAuthTries 3; the onboarding guide explains the error so the next person knows the cause.
Security implications
The server-side limit worked as intended and is worth keeping. The client-side fix reduces exposure:
fewer keys offered means less identity leakage to servers, and time-limited agent keys narrow the window
for misuse if a laptop is compromised. Avoid ForwardAgent yes to untrusted hosts; with a bastion, use
ProxyJump instead, which does not expose your agent to the bastion.
Prevention checklist
- Set
IdentitiesOnly yesand an explicitIdentityFileper host in~/.ssh/config. - Keep few keys in the agent, with lifetimes, and confirmation for production keys.
- Use
ssh -vto see which keys are offered andssh -Gto check effective configuration. - Prefer
ProxyJumpover agent forwarding. - Keep server
MaxAuthTrieslow; fix clients instead.
References
- ssh_config manual, IdentitiesOnly and IdentityFile: https://man.openbsd.org/ssh_config
- sshd_config manual, MaxAuthTries: https://man.openbsd.org/sshd_config
- ssh-add manual: https://man.openbsd.org/ssh-add
- OpenSSH release notes: https://www.openssh.com/releasenotes.html
Add a label
Embed this post
<iframe src="https://www.hibug.me/ssh-too-many-authentication-failures" width="700" height="420" frameborder="0" loading="lazy"></iframe>
I started as a Linux administrator in a hosting company and never really left the command line. Today I look after fleets of Linux servers, edge networking and CDN setups for web platforms, and I still do on-call shifts. My posts are the notes I wish I had found at three in the morning: the symptom, the commands that narrowed it down, the actual cause and the change that fixed it. I try to explain what each number in vmstat, iostat or ss output means, so you can reason about your own system instead of copying commands.
Comments
0No comments yet. Be the first to comment!
Sign In to post a comment.