Sitemap
yeah right

yeah right

Too Many Authentication Failures

9 min readOct 10, 2026

--

10 Oct 2026 · @John King

Press enter or click to view image in full size
Fail2ban image

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 yes

No config at hand? Same thing on the command line:

ssh -o IdentitiesOnly=yes -i ~/.ssh/shop.pub -p 2222 web@shared.example.net

The 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 no

Two 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 credentials
QT_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.net

The 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 2222

A 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.pub

On 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-2026

Private 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_ed25519

2. 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 no

The 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-deploy

Only 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.pub

In 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/ssh

Now only you have the proper rights and SSH is happy.

Bringing a new machine online

  1. Nextcloud client syncs the database and the ssh/ folder.
  2. 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 keepassxc

3. 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.conf

Then 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/config

6. 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-web

Look 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_keys on both accounts, replace the .pub in 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. IdentityFile with the .pub plus IdentitiesOnly yes, per host.
  • No silent fallback. PasswordAuthentication no on 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.

--

--