termal.in

← Blog

SSH errors, decoded: the ten you'll actually hit and how to fix them

· Termalin team sshtroubleshootingtutorial

SSH error messages are terse on purpose — the protocol won’t tell a stranger why it turned them away. That’s good security and bad ergonomics: the message you see is often two steps removed from the actual problem. This is a field guide to the ten errors you’ll actually meet, what each one really means, and the fastest route to a fix.

One tool before we start: ssh -v user@host (add up to -vvv). Nearly every mystery below stops being a mystery once you see which step of the handshake it dies on.

1. Connection refused

The machine is reachable, but nothing is listening on the port you knocked on. This one is almost never about you:

  • sshd isn’t running — systemctl status sshd from a console (VPS providers have a web console for exactly this moment);
  • it listens on a non-standard port — try ssh -p 2222, or check /etc/ssh/sshd_config for Port;
  • a firewall is actively rejecting (rather than dropping) the port.

If you just rebuilt the server, it’s the firewall. If it worked yesterday, sshd crashed or the port changed.

2. Connection timed out

Different from refused: your packets are vanishing. The host is down, the IP is wrong, or — most often on cloud boxes — a security group / network ACL silently drops port 22. Check the provider’s firewall rules first, then whether you’re on a network that blocks outbound 22 (hotel and office guest Wi-Fi love this; try port 443-based access or a different network to confirm).

3. Permission denied (publickey)

The all-time champion. The server only accepts key auth, and it didn’t accept any key you offered. In order of likelihood:

  • Wrong user. ubuntu on Ubuntu images, ec2-user on Amazon Linux, root on most bare VPSes. The same key with the wrong username produces exactly this error.
  • Your key wasn’t offered. ssh -v shows every key tried. If your key isn’t in the list, point at it explicitly: ssh -i ~/.ssh/id_ed25519 user@host.
  • The key isn’t on the server. Its public half must be one line in ~user/.ssh/authorized_keys — for that user, not root’s.
  • Server-side permissions. sshd refuses to honor authorized_keys if the home dir, ~/.ssh (700), or the file itself (600) is group-writable. This is the classic “I copied the key and it still doesn’t work”.

4. Permission denied when you expected a password prompt

If you wanted password auth and never got asked, the server has PasswordAuthentication no — most cloud images ship that way, and it’s the right default. Use the provider’s console or your existing key to get in, then add the new key properly rather than switching passwords back on.

5. Host key verification failed / REMOTE HOST IDENTIFICATION HAS CHANGED

The scary banner with the ASCII skull energy. The server presented a different key than the one you trusted before. Two explanations: the machine was legitimately rebuilt/reinstalled (overwhelmingly the common case), or something between you and the server is impersonating it (the case the warning exists for).

If — and only if — you know the server was rebuilt: ssh-keygen -R hostname removes the stale entry, and the next connect re-trusts. Don’t blindly script that removal into your workflow; the one time the warning is real, it’s the only warning you get.

6. Too many authentication failures

Your agent enthusiastically offered six keys, the server’s MaxAuthTries said enough. Tell the client to offer only the key you mean:

ssh -o IdentitiesOnly=yes -i ~/.ssh/the_right_key user@host

…or make it permanent in ~/.ssh/config per host. If you carry many keys, IdentitiesOnly yes under Host * will save you this error forever.

7. WARNING: UNPROTECTED PRIVATE KEY FILE

Your private key is readable by others, and the client refuses to use it. chmod 600 ~/.ssh/id_ed25519. On Windows this appears after copying keys between machines or out of a cloud drive — fix it via the file’s Security properties, or keep keys out of synced folders entirely.

8. client_loop: send disconnect: Broken pipe (the session that dies when you look away)

Idle connections dropped by a NAT router or aggressive firewall between you and the server. Keepalives fix it client-side:

Host *
    ServerAliveInterval 30
    ServerAliveCountMax 4

Two minutes of silence tolerated, packets every 30 seconds so the NAT table never forgets you. If sessions die under load rather than idle, that’s a different animal — look at MTU (VPNs especially) rather than keepalives.

9. no matching key exchange method found / no matching cipher

You’re talking to something old — a router, a switch, an appliance stuck on legacy crypto. Modern OpenSSH removed those algorithms for good reason. Re-enable them for that one host only, never globally:

Host ancient-switch
    KexAlgorithms +diffie-hellman-group14-sha1
    Ciphers +aes256-cbc

The error message names the algorithms the server offered; add the least-bad one it lists.

10. ssh_exchange_identification: read: Connection reset by peer

The TCP connection opened and was immediately slammed shut, before SSH even said hello. Usual suspects: fail2ban or DenyHosts has banned your IP (check /etc/hosts.deny and fail2ban’s jail from a console), sshd is overloaded (MaxStartups exhausted by a scanner hammering the port), or a load balancer health check is eating connections. If it’s fail2ban and it’s your own server, the fix is a console login and fail2ban-client unban <your-ip> — then move SSH off scanners’ radar or tighten the jail so you’re not next week’s collateral.


Make the fixes stick

Half of these are one-off fixes; the other half deserve a line in ~/.ssh/config so they never come back — keepalives, IdentitiesOnly, per-host ports and identities. Config beats memory.

The other thing that beats memory is a client that keeps state for you. Termalin stores per-host settings — port, user, key, keepalives — with the host itself, verifies servers on first connect and warns loudly when a fingerprint changes, and its status bar shows the machine’s vitals live, so “is the box even up?” stops being a diagnostic step. The Free tier has no host limits — grab it and retire a few of these errors permanently.

Try it on one host.

Termalin is a fast SSH client for you — and your agents.

Free tier · 14-day Pro trial · pricing