← Back to Blog DevOps & Sysadmin

SSH Troubleshooting Guide: Fixing Common Connection Errors

15 min read

SSH troubleshooting is a critical, unavoidable skill for developers, sysadmins, and DevOps engineers. Secure Shell (SSH) is the backbone of modern infrastructure management, but when it fails, it can completely halt your productivity. Whether you are dealing with a cryptic Permission denied (publickey) error, staring at a sudden Connection refused SSH message, or dealing with an alarming Host key verification failed warning, debugging the SSH protocol requires a structured, logical approach.

In this comprehensive guide, we will break down the top 10 most common SSH errors, diagnose exactly why they happen, and provide the precise commands to fix them. If you need to generate proper commands instantly, use our SSH command builder. If you suspect your cryptographic keys are outdated or corrupted, generate a fresh, secure pair using our privacy-first SSH key generator. At ZeroData Tools, we believe in local-only processing—your private keys and server IPs never leave your browser.

🚀 Quick Solution: The Sysadmin's First Move

Whenever an SSH connection fails, do not guess the problem. Append -vvv to your command. This enables maximum verbosity and shows you exactly where the handshake or authentication breaks down.

ssh -vvv user@hostname

1. Permission Denied (publickey)

The Permission denied (publickey) error is arguably the most frequent roadblock you will encounter. It explicitly means the server has rejected your connection because it could not authenticate your identity using the public keys it has on file. This usually happens when password authentication is disabled, and the server does not recognize the private key your client is offering.

Why it matters: Security best practices dictate disabling password authentication in favor of key-based auth. When it fails, you are locked out of your own infrastructure.

Client-Side Fixes:

  • Specify the correct key: Your client might be offering the wrong default key. Force it to use a specific key using the identity flag.
ssh -i ~/.ssh/id_ed25519 user@hostname

Server-Side Fixes:

  • Check authorized_keys: Ensure your public key (the .pub file) is correctly pasted into the server's ~/.ssh/authorized_keys file without any line breaks or missing characters.
  • Fix file permissions: SSH is notoriously strict about file permissions. If your server's permissions are too open, SSH will silently ignore the key files for safety. Run these commands on the server (via console or another active session):
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

2. Connection Refused SSH

Encountering a Connection refused SSH error indicates a network-level rejection. Your client successfully reached the target IP address, but the server actively refused the connection by sending a TCP RST (reset) packet.

Why it matters: This is rarely an authentication issue. It means the SSH service is either down, listening on a different port, or blocked by a strict local firewall that explicitly rejects packets rather than dropping them.

Diagnostic Steps:

First, verify that the SSH daemon is actually running on the server. If you have console access, check the service status:

sudo systemctl status sshd

If it is inactive, restart it:

sudo systemctl restart sshd

Check the Port:

Many sysadmins change the default SSH port from 22 to something else (e.g., 2222) to avoid automated bot scanners. If the server is listening on port 2222, connecting to port 22 will result in a connection refused. Specify the custom port in your command:

ssh -p 2222 user@hostname

To avoid typing this every time, you can configure your local setup. Check out our SSH config generator to automate port handling.

3. Host Key Verification Failed

The terrifying Host key verification failed message is actually SSH doing its job perfectly. The first time you connect to a server, SSH saves its cryptographic footprint (host key) in your local ~/.ssh/known_hosts file. If you connect again and the server's footprint has changed, SSH panics.

Why it matters: This protects you against Man-In-The-Middle (MITM) attacks. However, it also triggers legitimately when a server is rebuilt, an IP address is reassigned, or an EC2 instance is recreated.

The Fix:

If you are absolutely certain the server was legitimately rebuilt and this is not an attack, you must remove the old, offending key from your local known_hosts file. Use the ssh-keygen utility to remove the specific IP or hostname:

ssh-keygen -R hostname_or_ip_address

After running this, attempt the connection again. SSH will prompt you to accept the new fingerprint as if it were a brand new server.

4. Connection Timed Out

Unlike a refused connection, a timeout means your SSH request went into the void and no response ever came back. The client waited for the TCP handshake to complete, but the packets were dropped.

Common Causes: This is almost always a firewall issue, a routing problem, or a server that is completely offline. It could be AWS Security Groups, Google Cloud Firewall rules, or a local iptables/ufw configuration blocking port 22.

How to Troubleshoot:

  • Ping the server: Check if basic ICMP traffic reaches the host. ping target_ip
  • Trace the route: See where the packets are getting dropped. traceroute target_ip (or tracert on Windows).
  • Test the port: Use netcat to see if the port is reachable through firewalls.
nc -vz target_ip 22

If netcat times out, you must log into your cloud provider's console and ensure inbound TCP traffic on port 22 is allowed for your current IP address.

5. WARNING: UNPROTECTED PRIVATE KEY FILE!

This error is extremely loud and for good reason. SSH clients will aggressively refuse to use a private key file that has overly permissive file rights. If other users on your local machine can read your private key, your security is compromised.

The Solution:

You must restrict the permissions of your private key file so that only your user account has read access. No one else, not even the group, should be able to read it.

chmod 600 ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_ed25519

If you are on Windows using OpenSSH, you must modify the file properties. Right-click the key file, go to Properties > Security > Advanced, disable inheritance, and ensure only your user account has "Full control".

6. Too Many Authentication Failures

SSH clients have a feature (or flaw, depending on how you look at it) where they will automatically attempt to use every single private key loaded into your SSH Agent or stored in your ~/.ssh directory before falling back to a password.

Servers typically have a MaxAuthTries limit (usually 6). If you have 7 different SSH keys on your local machine, the SSH client will try them one by one. The server will drop the connection before your client ever gets to the correct key or prompts for a password.

The Fix:

You can tell your SSH client to strictly use only the key you specify in the command line, ignoring the others. Use the IdentitiesOnly flag:

ssh -i /path/to/correct_key -o IdentitiesOnly=yes user@hostname

If you want to make this permanent for a specific host, add it to your SSH config. For a deeper dive into optimal configurations, read our SSH complete guide.

7. No Matching Key Exchange Method Found

This error looks like cryptographic gibberish: Unable to negotiate with X.X.X.X port 22: no matching key exchange method found. Their offer: diffie-hellman-group1-sha1.

Why it happens: Cryptography evolves. Modern SSH clients (like recent versions of OpenSSH) deprecate old, insecure encryption algorithms. If you are trying to connect to a legacy switch, an old router, or an unpatched server that only supports ancient algorithms, the handshake fails.

The Fix:

You can force your modern SSH client to temporarily re-enable the legacy algorithm required by the old server using the -o KexAlgorithms flag.

ssh -o KexAlgorithms=+diffie-hellman-group1-sha1 user@legacy_hostname

Be warned: doing this means you are using weak encryption. You should strongly consider updating the firmware or SSH daemon on the target device.

8. Could Not Resolve Hostname

The ssh: Could not resolve hostname... Name or service not known error means your computer cannot convert the domain name you typed into an IP address.

Troubleshooting Steps:

  • Check for typos in your command.
  • Check your local ~/.ssh/config file. You might have defined a host alias improperly.
  • Verify DNS resolution using nslookup or dig:
dig yourhostname.com

If the DNS query fails, you need to fix your network's DNS settings or add a manual override in your local /etc/hosts file.

9. packet_write_wait: Broken Pipe

You successfully connect via SSH, run a long process, switch to another tab for five minutes, and when you return, your terminal is frozen. A minute later, you see packet_write_wait: Connection to X.X.X.X port 22: Broken pipe.

Why it happens: Stateful firewalls, NAT routers, and cloud load balancers track active TCP connections to save memory. If a connection is completely idle (no data transmitted) for a certain period, the router assumes the connection is dead and drops it from its state table.

The Fix:

You need to tell your SSH client to send a tiny "keep-alive" heartbeat packet to the server at regular intervals so the firewalls know the connection is still active.

Add this to your local ~/.ssh/config file:

Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3

10. Bad Owner or Permissions on ~/.ssh/config

If you try to organize your SSH connections using a config file, you might run into an error stating Bad owner or permissions on /home/user/.ssh/config. Similar to the unprotected private key error, SSH enforces strict permissions on its configuration files to prevent malicious local users from hijacking your connection aliases.

The Fix:

Ensure that the config file is owned by your user account and that no one else can read or write to it.

chown $USER:$USER ~/.ssh/config
chmod 600 ~/.ssh/config

Masterclass: Advanced Sysadmin Debugging

When the standard fixes don't work, you must escalate to advanced sysadmin debugging. This involves cross-referencing verbose client output with server-side logs.

Step 1: The Verbose Client Log (-vvv)

Running ssh -vvv provides a mountain of data. Here is what you should look for:

  • debug1: Reading configuration data: Shows exactly which config files are being parsed.
  • debug1: Connecting to...: Shows the IP and port. If it hangs here, it's a firewall/network issue.
  • debug1: Local version string / Remote protocol version: Ensures both sides are speaking the same protocol.
  • debug1: Authentications that can continue: This is vital. It tells you what methods the server actually allows (e.g., publickey,password).
  • debug1: Offering public key: Shows which specific key file is being tested against the server.

Step 2: Server-Side Authentication Logs

If the client logs show that the key was offered but rejected, the absolute truth lies on the server. You need to read the authentication logs. If you have an alternate way into the server (like a cloud provider's web console), check these files.

On Debian and Ubuntu based systems:

sudo tail -f /var/log/auth.log | grep sshd

On Red Hat, CentOS, Fedora, and Amazon Linux systems:

sudo tail -f /var/log/secure | grep sshd

Common server-side log messages include:

  • Authentication refused: bad ownership or modes for directory: The server's ~/.ssh directory has the wrong permissions.
  • User not allowed because not listed in AllowUsers: The sshd_config file has an AllowUsers directive, and your username is missing from it.
  • Connection closed by authenticating user: The client gave up, often due to the "too many authentication failures" issue.

Step 3: SELinux Contexts (RHEL/CentOS Specific)

If you are on an SELinux-enforced system (like RHEL, AlmaLinux, or Rocky Linux), having the correct Unix permissions (chmod 600) is not enough. The files must also have the correct SELinux security context. If you moved your .ssh directory or created it as the root user, the context might be wrong.

Restore the correct SELinux contexts with this command:

restorecon -Rv ~/.ssh

Conclusion

Mastering SSH troubleshooting turns hours of frustrating downtime into a quick 2-minute diagnostic process. By understanding the difference between network timeouts, cryptographic mismatches, and strict permission requirements, you can identify the root cause immediately. Remember: never guess—always use ssh -vvv and read the logs.

Secure your infrastructure properly. Don't rely on passwords, manage your keys securely, and leverage local-only tools like ZeroData Tools to maintain ultimate privacy while building your configurations.

Frequently Asked Questions

Why do I get Permission denied (publickey) even with the right password?
This occurs when the SSH server is configured to disable password authentication entirely and only accept cryptographic keys. You must upload your public key to the server's authorized_keys file.
What does the ssh -vvv command actually do?
Adding -vvv to your SSH command enables maximum verbosity debugging. It prints out every step of the connection process, including DNS resolution, key exchange algorithms, and authentication attempts, which is critical for finding where the connection fails.
How do I fix the 'broken pipe' error on idle connections?
Add 'ServerAliveInterval 60' to your ~/.ssh/config file. This sends a null packet to the server every 60 seconds, preventing firewalls or load balancers from dropping the idle TCP connection.
Can a firewall block port 22 and cause Connection refused SSH?
Yes, but usually firewalls cause 'Connection timed out' by dropping packets silently. 'Connection refused' means the server actively rejected the connection, which usually indicates the SSH daemon isn't running or is listening on a different port.
How do I bypass Host key verification failed temporarily?
You can bypass it for a single command using: ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null user@host. Note that this makes you vulnerable to Man-In-The-Middle attacks and should only be used on trusted local networks.
What are the exact correct permissions for the .ssh directory and keys?
The ~/.ssh directory must be 700 (drwx------). Private keys (id_rsa, id_ed25519) must be 600 (-rw-------). Public keys (.pub) can be 644 (-rw-r--r--). The ~/.ssh/authorized_keys file should be 600.
How does misconfigured DNS cause SSH timeouts?
If the SSH server is configured with UseDNS yes (the default on many older systems), it attempts a reverse DNS lookup on your IP address. If the DNS server is unresponsive, the connection will hang and eventually time out.
Why does SSH complain about an UNPROTECTED PRIVATE KEY FILE?
SSH enforces strict security standards for your private keys. If your private key file is readable by other users on your system (e.g., permissions are 644 instead of 600), the SSH client will refuse to use it to prevent compromise.
What is the difference between Connection refused and Connection timed out?
Connection refused means a router or server actively responded with an RST packet (nothing is listening on that port). Connection timed out means your request disappeared into a black hole (dropped by a firewall) and no response ever arrived.
How do I resolve 'Too many authentication failures'?
This happens when your SSH client offers too many incorrect keys to the server before trying the right one. Fix it by specifying the exact key using 'ssh -i /path/to/key -o IdentitiesOnly=yes user@host'.
How do I find out which SSH key is actually being used?
Run your SSH command with the -v flag. Look for lines stating 'Offering public key' or 'Will attempt key'. This reveals exactly which files the client is trying to authenticate with.
Why do I get a protocol mismatch or no matching key exchange method error?
This occurs when connecting to a very old server with a modern client (or vice versa). Modern SSH clients disable legacy algorithms like ssh-rsa or diffie-hellman-group1-sha1. You must explicitly enable them using the -o KexAlgorithms flag.
Is it safe to permanently use StrictHostKeyChecking no?
No. Disabling host key checking globally exposes you to Man-In-The-Middle (MITM) attacks where an attacker intercepts your connection and steals your credentials or data. Only use it for ephemeral CI/CD environments where hosts change constantly.
How can I test SSH network connectivity without actually logging in?
You can test basic port connectivity using 'nc -vz hostname 22' or 'telnet hostname 22'. If you see the SSH banner (e.g., SSH-2.0-OpenSSH), the network path is clear and the daemon is running.
What log files should I check on the server for SSH authentication failures?
On Debian/Ubuntu systems, check /var/log/auth.log. On RHEL/CentOS/Fedora systems, check /var/log/secure. You can also view live logs using 'journalctl -u sshd -f' on systemd-based distributions.