Too Many Authentication Failures
10 Oct 2026 · @John King
How a password manager, a file manager and fail2ban teamed up to lock me out of a server for an hour, and the setup I use now so it never happens again.
Parts of this article where based on an AI assisted draft.
It was a Saturday afternoon. I only wanted to open a client’s SFTP folder in Dolphin and copy a few files. One account worked. The second one, on the same server, just hung. A few clicks later, both were dead. The server no longer answered at all.
Nothing was wrong with the server. Nothing was wrong with my password. The problem was my own SSH keys, politely offered one after another until the server decided I was an attacker.
This is the write-up of how I got there and how I got out.
The setup
I run a small web and IT services business and teach on the side. That means a lot of servers, a lot of customers and a lot of SSH keys.
- KeePassXC as SSH agent. All private keys live inside my KeePassXC database. When I unlock it, KeePassXC loads the keys into the running
ssh-agent. No private key files on disk. - Many keys. Over the years the agent collected well over half a dozen of them.
- Fedora with KDE Plasma. I use Dolphin for quick SFTP work, the terminal for everything else.
- A shared hosting server on a non-standard SSH port, with two accounts: one with key login, one with password login. The password was stored in KWallet by Dolphin.
Every piece of this is reasonable on its own. Together they form a nice little trap.
Why “Too many authentication failures” happens
An SSH agent does not know which key belongs to which server. So the client offers every key it holds, one by one. Each rejected key counts as a failed attempt. OpenSSH servers allow six by default (MaxAuthTries). With seven keys in the agent, you are out before the right one, or the password prompt, ever gets a turn.
The classic fix is IdentitiesOnly yes. It tells the client to offer only the identities you name explicitly. The part I didn't know: IdentityFile can point to the public key. The client then picks the matching private key from the agent. The private key never has to touch the disk.
Host shop-web
HostName shared.example.net
Port 2222
User web
IdentityFile ~/.ssh/shop.pub
IdentitiesOnly yesNo config at hand? Same thing on the command line:
ssh -o IdentitiesOnly=yes -i ~/.ssh/shop.pub -p 2222 web@shared.example.netThe public key is not secret. It already sits in authorized_keys on the server. So nothing about the agent's purpose is lost: KeePassXC still guards the private key. The config only adds the one thing the agent cannot know, which key goes where.
For the password account it’s the reverse. Switch public key auth off entirely:
Host shop-deploy
HostName shared.example.net
Port 2222
User deploy
PubkeyAuthentication noTwo aliases, same server, no more guessing.
Where Dolphin turned it into a lockout
In a terminal, the error is right there and you fix it in a minute. Dolphin is a different story.
Dolphin talks SFTP through KIO, KDE’s I/O layer, which uses libssh rather than the OpenSSH client. When authentication failed, Dolphin showed nothing. No error, no dialog, just a view that seemed frozen.
What I didn’t see:
- Each connection offered every key in the agent first, then tried the password from KWallet.
- Dolphin can open more than one connection per folder (listing, previews, the info panel), each its own SSH session.
- Every retry multiplied the count.
A few clicks produced quite a few failed attempts in a couple of minutes. The hoster runs fail2ban, and fail2ban did its job. My IP was banned. That also killed the account that had worked fine all along.
Getting the worker to talk
A useful trick here is to bypass Dolphin and run the same connection through kioclient with debug logging on:
kquitapp6 kiod6 # drop cached workers and credentialsQT_LOGGING_RULES="kf.kio.workers.sftp.debug=true" \
KIO_SFTP_LOG_VERBOSITY=4 \
kioclient ls 'sftp://deploy@shared.example.net:2222/'KIO_SFTP_LOG_VERBOSITY turns on libssh's own logging, roughly the equivalent of ssh -vvv. Mine ended like this:
ssh_connect_host_nonblocking: Connecting to host shared.example.net [203.0.113.10] port 2222
ssh_connect: Actual timeout : 30000
ssh_connect: Timeout connecting to shared.example.netThe connection never got past TCP. No SSH banner or auth step. A failed login looks different: the connection opens, then authentication fails. A silent 30 second timeout means packets are being dropped. That’s a ban.
To confirm without making things worse:
nc -vz -4 -w 5 shared.example.net 2222A phone hotspot is the quickest way back in, since the ban is tied to your IP. Otherwise: stop trying, wait it out, or ask the hoster. Retrying during a ban can extend it.
Cleaning up KWallet
KWallet also held a wrong password from my attempts. In KWalletManager the entries hide one level deeper than you’d expect: Passwords → Maps → the entry. KIO stores its credentials as maps, so they never appear directly under the folder. Delete the wrong entry, then run kquitapp6 kiod6 so KIO forgets its cached copy.
For Dolphin, the order is: agent keys first, KWallet password second. If the keys exhaust the limit, KWallet never even gets asked.
The fix: keys first, passwords only when forced
Once the ban lifted, I didn’t want two auth methods on one server anymore. Keys are not the optional upgrade here, they’re the default. No secret travels over the wire, brute force is off the table, and a stale password in KWallet can’t trip fail2ban.
1. One key, stored in KeePassXC
ssh-keygen -t ed25519 -C "shop@keepassxc-2026" -f /tmp/id_ed25519
mkdir -p ~/.ssh && chmod 700 ~/.ssh
mv /tmp/id_ed25519.pub ~/.ssh/shop.pubOn Keys
There is no standard ending on public and private keys. But to just give you a warm fuzzy feeling that you have the right one:
Public keys look like this
ssh-ed25519 .............. shop@keepassxc-2026Private keys start with
-----BEGIN OPENSSH PRIVATE KEY-----The comment “shop@keepassxc-2026” has no further meaning but will appear on the host in the authorized_keys, so it makes sense to name it something recognizable also if you ever want to revoke a certain key. In KeePassXC: new entry, attach /tmp/id_ed25519 under Advanced → Attachments, then select it in the SSH Agent tab and enable Add key to agent when database is opened/unlocked.
Get yeah right’s stories in your inbox
Join Medium for free to get updates from this writer.
A few things I wondered about along the way:
- The entry’s username and URL fields are ignored by the agent. Use them for notes.
- The password field is the key’s passphrase, if it has one.
- The attachment name doesn’t matter. You pick the file explicitly. KeePassXC shows the fingerprint once it recognises the key.
Check it’s loaded, then shred the file:
grep -qF "$(cut -d' ' -f2 ~/.ssh/shop.pub)" <(ssh-add -L) && echo OK
shred -u /tmp/id_ed255192. Put the key on both accounts, carefully
This step still uses the password, so it must not walk into the same trap:
ssh-copy-id -f -i ~/.ssh/shop.pub -p 2222 \
-o PubkeyAuthentication=no web@shared.example.net
ssh-copy-id -f -i ~/.ssh/shop.pub -p 2222 \
-o PubkeyAuthentication=no deploy@shared.example.net-f skips the pre-check, which would open an extra connection and offer keys. PubkeyAuthentication=no goes straight to the password prompt. One attempt per account. If you mistype, stop and wait rather than hammering.
No shell on the hosting? Most control panels have a field for authorized keys.
3. Config: one alias per account and disable fallback
Host shop-web
HostName shared.example.net
Port 2222
User web
IdentityFile ~/.ssh/shop.pub
IdentitiesOnly yes
PasswordAuthentication no
KbdInteractiveAuthentication no
Host shop-deploy
HostName shared.example.net
Port 2222
User deploy
IdentityFile ~/.ssh/shop.pub
IdentitiesOnly yes
PasswordAuthentication no
KbdInteractiveAuthentication noThe last two lines of each Host block matter more than they look. If KeePassXC is locked, the agent is empty. Without them, SSH falls back to a password prompt, and a cancelled prompt can count as a failure. We don't want that. With them, you get an immediate Permission denied (publickey). Unlock KeePassXC, try again, done.
4. Test in the terminal, then Dolphin
ssh shop-web
ssh shop-deployOnly after both work: sftp://shop-web/ and sftp://shop-deploy/ in Dolphin, saved as places. As the username is in the config there is no web@ here.
One caveat. I’m not certain libssh honours IdentitiesOnly. If it doesn't, Dolphin may still offer every agent key. The safe habit is to keep the number of keys loaded at once below the server's limit, and load rarely used keys on demand from KeePassXC. Check with ssh-add -l what is loaded remove with ssh-add -D to clear the list. Or use KeepassXC build in Clear SSH Agent.
Five computers, one setup
I work on three laptops and two workstations, plus a smartphone. My KeePassXC database already syncs through a self-hosted Nextcloud. So the key reaches every machine without any extra work, and the server never needs to change when I add a device.
The only other thing to share is the SSH config and the public keys. Neither is secret, so they go into Nextcloud too:
~/Nextcloud/ssh/config
~/Nextcloud/ssh/shop.pubIn that shared config, IdentityFile points into the Nextcloud folder (~/Nextcloud/ssh/shop.pub). That requires the folder to sit at the same path on every machine. One extra step is needed though. We it one caveat here. For SSH to trust private (or public) keys they must be readable (and writable) by the current user only. Nextcloud does not know anything about file permissions and public key files created or synced in this way will have owner read/write and group and world read rights, ssh will simply not accept them. The simples trick is to make the whole ~/Nextcloud/ssh folder 0700, only read-writeable and listable (is that a word?) by the user.
chmod 700 ~/Nextcloud/sshNow only you have the proper rights and SSH is happy.
Bringing a new machine online
- Nextcloud client syncs the database and the
ssh/folder. - Install KeePassXC from the distro. Make sure to not use the Flatpak as the sandbox gets in the way of the agent socket.
sudo dnf install keepassxc3. Check that an agent runs: echo $SSH_AUTH_SOCK. If it's empty:
systemctl --user enable --now ssh-agent
mkdir -p ~/.config/environment.d
echo 'SSH_AUTH_SOCK=${XDG_RUNTIME_DIR}/ssh-agent.socket' > ~/.config/environment.d/ssh-agent.confThen log out and back in.
4. In KeePassXC, enable SSH Agent integration and Start on login. These are per-device settings and are not stored in the database.
5. Pull in the shared config, keep the local file for machine-specific entries:
mkdir -p ~/.ssh && chmod 700 ~/.ssh
echo 'Include ~/Nextcloud/ssh/config' >> ~/.ssh/config
chmod 600 ~/.ssh/config6. Test: ssh-add -l, then ssh shop-web and ssh shop-deploy. Confirm the host fingerprint once.
7. Add the Dolphin places.
To test and make sure the config really hit do:
ssh -G shop-webLook out for and check the host, user and hostname.
The phone only reads the database (KeePassDX works well). The private key stays off it.
Two things to keep in mind
- Sync conflicts. Edit the database on two devices at once and Nextcloud produces a conflict copy. KeePassXC can merge it via Database → Merge from database.
- One key for all devices is convenient, but revoking it hits every machine. If a laptop goes missing: new key, swap it in
authorized_keyson both accounts, replace the.pubin Nextcloud. Every other machine picks up the change on its next sync.
What I took away
Why does nobody seem to care about this? Because most people never hit the combination. They have two or three keys, not ten. They use key login only. Their own servers whitelist them. And in a terminal the error is plain, so they add IdentitiesOnly and forget about it. The GUI is where a five minute config detail turns into an hour on the bench.
Lessons learned:
- Keys are the first choice. Passwords only where the hoster forces them.
- Many keys in an agent need a map.
IdentityFilewith the.pubplusIdentitiesOnly yes, per host. - No silent fallback.
PasswordAuthentication noon key-only hosts. - New connection? Test in the terminal first. One connection at the time and limit retries. Dolphin comes after.
I filed a bug with KDE (product kio-extras, component SFTP). The request is modest: show an error instead of hanging, and don’t retry silently after auth failures. Each retry counts against someone’s fail2ban.
A word on the help
I worked through all of this in a single chat with Claude, Anthropic’s AI assistant, and I’ll give it fair credit. It knew that IdentityFile accepts a public key. It read the libssh timeout correctly as a ban rather than an auth problem. It pointed me to the hidden Maps level in KWallet and the KIO_SFTP_LOG_VERBOSITY switch. When it forgot the step that moves the public key into place, it apologized and fixed it. It also flagged where it wasn't sure, like libssh and IdentitiesOnly, instead of bluffing.
The decisions and the testing were mine. But as a troubleshooting partner on a Saturday afternoon with a locked-out server, it saved me a lot more than the hour I lost.






