Error Medic

SSH Connection Refused: How to Diagnose and Fix Every Variant

Fix SSH connection refused, permission denied, segfault, and slow connections with step-by-step commands. Covers sshd, firewall, keys, and PAM issues.

Last updated:
Last verified:
2,054 words
Key Takeaways
  • 'Connection refused' means the TCP handshake never completed — sshd is not listening, a firewall is dropping packets, or you are hitting the wrong host/port
  • 'Permission denied (publickey)' means sshd is reachable but authentication failed — wrong key, wrong user, or bad file permissions on ~/.ssh/authorized_keys
  • 'Connection timed out' usually points to a firewall silently dropping packets rather than an RST, use nc or nmap to confirm the port state
  • SSH slowness on connect is almost always DNS reverse-lookup (UseDNS yes) or GSSAPI negotiation — both are one-line sshd_config fixes
  • A segfault in ssh or sshd is nearly always a version/algorithm mismatch or a corrupted host key — check OpenSSH version and regenerate keys if needed
Fix Approaches Compared
SymptomRoot CauseFix CommandTimeRisk
Connection refusedsshd not runningsystemctl start sshd<1 minLow
Connection refusedWrong portssh -p 2222 user@host<1 minNone
Connection refusedFirewall blocking 22ufw allow 22/tcp or iptables -I INPUT -p tcp --dport 22 -j ACCEPT2 minMedium
Permission denied (publickey)authorized_keys permissionschmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys<1 minLow
Permission denied (publickey)Wrong key loadedssh -i ~/.ssh/id_ed25519 user@host<1 minNone
Permission denied (publickey)SELinux/AppArmor labelrestorecon -Rv ~/.ssh2 minLow
Slow SSH loginUseDNS reverse lookupSet UseDNS no in sshd_config1 minLow
Slow SSH loginGSSAPI negotiationssh -o GSSAPIAuthentication=no<1 minNone
SSH segfaultAlgorithm mismatch/old keyRemove stale host key, reconnect2 minLow
Host key changed warningMITM or rebuilt hostssh-keygen -R hostname<1 minLow

Understanding SSH Connection Errors

SSH errors fall into four distinct failure layers: network/transport (TCP never connects), authentication (sshd rejects your credentials), session (shell or subsystem fails post-auth), and performance (connects but slowly). Misdiagnosing the layer wastes hours. This guide works top-down.


Layer 1 — Transport: "Connection refused" and "Connection timed out"

Step 1: Confirm the exact error message

Run ssh with maximum verbosity to see exactly where the handshake fails:

ssh -vvv user@192.0.2.10

Key lines to look for:

  • connect to host 192.0.2.10 port 22: Connection refused — TCP RST received; sshd is not listening on this address/port.
  • connect to host 192.0.2.10 port 22: Connection timed out — Firewall is silently dropping packets; no RST arrived.
  • ssh: connect to host 192.0.2.10 port 22: No route to host — Routing or network-layer problem.
Step 2: Verify sshd is running
# On the remote host:
systemctl status sshd          # systemd systems (RHEL, Ubuntu 16+, Debian 8+)
service ssh status              # SysV / older Ubuntu naming
ps aux | grep sshd

If sshd is stopped, start it and check for config errors:

sshd -t                        # Test config without starting
systemctl start sshd
journalctl -u sshd -n 50       # Recent sshd log entries

Common startup failures:

  • Port already in use: sshd: Address already in use — Another process holds port 22. Find it: ss -tlnp | grep :22
  • Bad config syntax: sshd -t will report the offending line.
  • Missing host key: sshd: no hostkeys available — regenerate: ssh-keygen -A
Step 3: Check which address and port sshd is bound to
ss -tlnp | grep sshd
# Expected: LISTEN 0 128 0.0.0.0:22 ...

If sshd listens on a non-standard port (e.g., 2222), connect with ssh -p 2222. The port is set in /etc/ssh/sshd_config via the Port directive.

Step 4: Rule out firewall
# Test reachability without ssh from a third host or using nc:
nc -zv 192.0.2.10 22
# Open:    succeeded! -> sshd is up, problem is elsewhere
# refused: -> sshd not listening
# timeout: -> firewall dropping

# On the remote host — inspect active firewall rules:
iptables -L INPUT -n -v | grep 22
nft list ruleset | grep 22
ufw status verbose
firewall-cmd --list-all        # firewalld (RHEL/CentOS 7+)

To open port 22 immediately:

# UFW:
ufw allow ssh

# iptables (does not persist across reboots without iptables-persistent):
iptables -I INPUT -p tcp --dport 22 -j ACCEPT

# firewalld:
firewall-cmd --permanent --add-service=ssh
firewall-cmd --reload

Layer 2 — Authentication: "Permission denied (publickey)"

Once the TCP connection is established, sshd authenticates you. The most common error is:

debug1: Offering public key: /home/user/.ssh/id_ed25519
debug1: Authentications that can continue: publickey
permission denied (publickey).
Step 1: Check the correct key is being offered
ssh -vvv user@host 2>&1 | grep 'Offering\|Trying\|identity'

If your key is not listed, the ssh-agent may not have it loaded:

ssh-add -l                     # List loaded keys
ssh-add ~/.ssh/id_ed25519      # Add your key

Force a specific key:

ssh -i ~/.ssh/id_ed25519 user@host
Step 2: Verify authorized_keys on the server
cat ~/.ssh/authorized_keys     # Should contain your public key

Permission requirements — any deviation causes silent rejection:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
ls -la ~/.ssh/                 # owner must be the login user, not root

On SELinux-enforcing systems (RHEL, CentOS, Fedora), wrong file context causes the same symptom even with correct permissions:

ls -Z ~/.ssh/authorized_keys   # Check context
restorecon -Rv ~/.ssh          # Restore correct context
Step 3: Check sshd_config on the server
grep -E 'PubkeyAuthentication|AuthorizedKeysFile|PasswordAuthentication|PermitRootLogin|AllowUsers|DenyUsers' /etc/ssh/sshd_config

Key settings that block login:

  • PubkeyAuthentication no — must be yes
  • AuthorizedKeysFile pointing to a non-default path
  • AllowUsers or AllowGroups that excludes your user
  • PermitRootLogin no when logging in as root

After editing sshd_config, always reload safely (do not restart with an active session):

sshd -t && systemctl reload sshd
Step 4: Inspect /var/log/auth.log or journald
tail -f /var/log/auth.log                   # Debian/Ubuntu
journalctl -fu sshd                         # systemd
grep sshd /var/log/secure | tail -30        # RHEL/CentOS

Telltale log messages:

  • Authentication refused: bad ownership or modes for directory /home/user/.ssh — fix with chmod 700 ~/.ssh
  • User user from 1.2.3.4 not allowed because not listed in AllowUsers — update AllowUsers
  • fatal: Access denied for user root by PAM — PAM policy blocking login (check /etc/pam.d/sshd)

Layer 3 — Performance: Slow SSH Login

A 5–30 second pause before the password/key prompt is almost always one of two things:

DNS reverse lookup: sshd tries to resolve the client IP. Fix in /etc/ssh/sshd_config:

UseDNS no

GSSAPI negotiation: Kerberos probes time out on non-domain machines. Fix client-side (no server change needed):

ssh -o GSSAPIAuthentication=no user@host
# Make permanent in ~/.ssh/config:
Host *
    GSSAPIAuthentication no

Layer 4 — Crashes: "ssh segfault" / Process Aborted

A segfault in the ssh client or sshd daemon is uncommon but happens in three scenarios:

  1. Algorithm incompatibility between old server and new client. OpenSSH 8.8+ disabled RSA/SHA-1. If the server only supports ssh-rsa, the handshake aborts:
# Temporary workaround (client side):
ssh -o PubkeyAcceptedAlgorithms=+ssh-rsa -o HostKeyAlgorithms=+ssh-rsa user@host

# Permanent fix: update openssh-server on the remote host to 8.x+
  1. Corrupted server host key. Regenerate all host keys:
rm /etc/ssh/ssh_host_*
ssh-keygen -A
systemctl restart sshd
  1. Stale known_hosts entry after server rebuild:
# Client side:
ssh-keygen -R hostname
ssh-keygen -R 192.0.2.10

Host Key Changed Warning

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Do not blindly remove the key if you are on a production host — this warning can indicate a man-in-the-middle attack. Verify the new fingerprint out-of-band (console, cloud dashboard, vendor key fingerprint API) before removing:

# Only after verifying legitimacy:
ssh-keygen -R hostname

Quick Reference Checklist

  1. ssh -vvv — identify failure layer
  2. systemctl status sshd — is sshd running?
  3. ss -tlnp | grep sshd — what address/port?
  4. nc -zv host 22 — firewall or sshd?
  5. chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys
  6. grep -E 'AllowUsers|PubkeyAuth' /etc/ssh/sshd_config
  7. journalctl -u sshd -n 50 — auth log for server-side denial
  8. UseDNS no in sshd_config — fix slow login
  9. ssh-keygen -A — regenerate missing/corrupt host keys
  10. sshd -t && systemctl reload sshd — safe config reload

Frequently Asked Questions

bash
#!/usr/bin/env bash
# ssh-diagnose.sh — Run on the CLIENT to diagnose SSH connection issues
# Usage: bash ssh-diagnose.sh user@host [port]

TARGET="${1:-}"
PORT="${2:-22}"

if [[ -z "$TARGET" ]]; then
  echo "Usage: $0 user@host [port]"
  exit 1
fi

HOST="${TARGET##*@}"

echo "=== 1. TCP reachability (nc) ==="
nc -zv -w 5 "$HOST" "$PORT" 2>&1 && echo "[OK] Port $PORT open" || echo "[FAIL] Port $PORT closed or filtered"

echo ""
echo "=== 2. SSH verbose connect (first 40 lines) ==="
ssh -vvv -p "$PORT" -o ConnectTimeout=10 -o BatchMode=yes "$TARGET" exit 2>&1 | head -40

echo ""
echo "=== 3. Loaded SSH keys ==="
ssh-add -l 2>/dev/null || echo "[WARN] ssh-agent not running or no keys loaded"

echo ""
echo "=== 4. Known hosts entry for $HOST ==="
ssh-keygen -F "$HOST" 2>/dev/null || echo "[INFO] No known_hosts entry for $HOST"

echo ""
echo "=== 5. Client SSH config for $HOST ==="
ssh -G -p "$PORT" "$TARGET" 2>/dev/null | grep -E 'hostname|port|user|identityfile|gssapi|pubkeyauthentication'

echo ""
echo "=== REMOTE: Run these on the server ==="
cat <<'REMOTE'
# Check sshd status:
systemctl status sshd

# Check listening address and port:
ss -tlnp | grep sshd

# Check firewall:
ufw status verbose || firewall-cmd --list-all || iptables -L INPUT -n -v | grep 22

# Check authorized_keys permissions:
ls -la ~/.ssh/authorized_keys

# Check sshd_config for auth restrictions:
grep -E 'PubkeyAuth|PasswordAuth|AllowUsers|DenyUsers|PermitRoot|AuthorizedKeysFile' /etc/ssh/sshd_config

# Tail the auth log:
journalctl -u sshd -n 30 --no-pager
# or: tail -30 /var/log/auth.log

# Test sshd config syntax:
sshd -t && echo "Config OK"
REMOTE
E

Error Medic Editorial

Error Medic Editorial is a team of senior DevOps and SRE engineers with combined experience across Linux, cloud infrastructure, and distributed systems. Articles are peer-reviewed against current documentation and tested on live systems before publication.

Sources

Related Articles in SSH

Explore More Linux Sysadmin Guides