SSH Connection Refused: Troubleshooting Guide

Systematically diagnose and fix SSH connection refused errors — covering sshd service status, firewall rules, key authentication failures, SSH config issues, and verbose debugging.

Error Messages Explained

SSH connection errors are specific and each points to a different root cause:

Error Message Root Cause
Connection refused sshd is not running, or port is wrong
Connection timed out Firewall blocking the port
No route to host Network routing problem
Permission denied (publickey) Key authentication failure
Host key verification failed Server fingerprint changed
Connection reset by peer sshd crashed or network issue

Understanding which error you see narrows the diagnosis immediately.

Check sshd Service Status

The most common cause of "connection refused" is the SSH daemon not running on the server.

# Check if sshd is running (on the server)
sudo systemctl status ssh        # Ubuntu/Debian
sudo systemctl status sshd       # RHEL/CentOS/Fedora

# Start it if stopped
sudo systemctl start ssh
sudo systemctl enable ssh        # Auto-start on boot

# Check which port sshd is listening on
sudo ss -tlnp | grep ssh
sudo netstat -tlnp | grep sshd

# View sshd logs for startup errors
sudo journalctl -u ssh --no-pager -n 50
sudo tail -50 /var/log/auth.log  # Debian/Ubuntu alternative

If sshd fails to start, the log will show the reason:

# Common sshd startup failures:
# - Invalid configuration: sudo sshd -t (test config)
# - Missing host keys: sudo ssh-keygen -A
# - Port already in use: sudo ss -tlnp | grep :22

Verify Port and Firewall Rules

By default SSH listens on port 22, but many servers move it to a non-standard port (2222, 2200, etc.) to reduce automated attacks.

# Scan to find the actual SSH port (from a different machine)
nmap -p 1-65535 -sV --open TARGET_IP

# Or try common alternatives
ssh -p 2222 user@TARGET_IP
ssh -p 2200 user@TARGET_IP

# On the server: check sshd_config for Port directive
grep "^Port" /etc/ssh/sshd_config

Firewall checks on the server:

# UFW (Ubuntu)
sudo ufw status verbose
# If SSH is blocked:
sudo ufw allow ssh          # Allows port 22
sudo ufw allow 2222/tcp     # If using custom port

# iptables
sudo iptables -L INPUT -n -v | grep -E "22|ssh"

# Allow SSH with iptables
sudo iptables -I INPUT -p tcp --dport 22 -j ACCEPT

# firewalld (RHEL/CentOS)
sudo firewall-cmd --list-all
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload

For cloud servers (AWS, GCP, Azure):

The cloud provider's security group or network ACL may be blocking port 22, regardless of the OS-level firewall. Check:

  • AWS: EC2 Security Groups → Inbound rules → Ensure port 22 from your IP
  • GCP: VPC → Firewall rules → default-allow-ssh exists
  • Azure: Network Security Groups → Inbound security rules

SSH Key Authentication Failures

Permission denied (publickey) means sshd is running and reachable, but your key is not accepted.

# Check that your public key is in authorized_keys on the server
cat ~/.ssh/authorized_keys

# Verify permissions (critical — SSH ignores keys if permissions are wrong)
ls -la ~/.ssh/
# .ssh directory must be 700
# authorized_keys must be 600

# Fix permissions
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

On the client side:

# List keys loaded in the SSH agent
ssh-add -l

# Add your private key to the agent
ssh-add ~/.ssh/id_rsa
ssh-add ~/.ssh/id_ed25519

# Specify key explicitly (bypasses agent)
ssh -i ~/.ssh/my_key user@TARGET_IP

# Check that the public key on the server matches your private key
# On client: get public key fingerprint
ssh-keygen -l -f ~/.ssh/id_ed25519.pub

# On server: check authorized_keys for that fingerprint
ssh-keygen -l -f ~/.ssh/authorized_keys

Check sshd_config for restrictions:

grep -E "^(PubkeyAuthentication|AuthorizedKeysFile|PermitRootLogin|AllowUsers|DenyUsers)" /etc/ssh/sshd_config

Key settings: - PubkeyAuthentication yes — Must be enabled - AuthorizedKeysFile .ssh/authorized_keys — Points to the right file - AllowUsers alice bob — If set, only listed users can connect - PermitRootLogin no — Root cannot log in (common security hardening)

SSH Config File Issues

The ~/.ssh/config file on the client side controls connection parameters per host. A misconfiguration here can cause unexpected failures.

cat ~/.ssh/config

A typical config entry:

Host myserver
    HostName 192.168.1.100
    User ubuntu
    Port 22
    IdentityFile ~/.ssh/id_ed25519
    ServerAliveInterval 60
    ServerAliveCountMax 3

Common config mistakes:

  • Wrong HostName — An old IP that has changed
  • Wrong IdentityFile path — Key file does not exist
  • Conflicting Host blocks — A wildcard Host * block that overrides specific entries
  • Wrong User — The username does not exist on the server

Jump Host and ProxyJump

For servers behind a bastion host or in a private network, you need ProxyJump:

# Connect through a jump host (bastion)
ssh -J [email protected] [email protected]

# Using ProxyJump in ~/.ssh/config
# In ~/.ssh/config:
Host bastion
    HostName bastion.example.com
    User jumphost_user

Host private-server
    HostName 192.168.10.5
    User target_user
    ProxyJump bastion

# Then connect directly
ssh private-server

If ProxyJump fails:

# Test the bastion connection first
ssh [email protected]

# Verify the bastion can reach the target
ssh [email protected] "nc -zv 192.168.10.5 22"

Debugging with ssh -vvv

The most powerful SSH diagnostic tool is verbose mode. -v gives basic info, -vvv gives exhaustive detail.

ssh -vvv user@TARGET_IP 2>&1 | head -100

Key lines to look for in the output:

# Connection established (TCP is working)
debug1: Connecting to TARGET_IP port 22.
debug1: Connection established.

# Server fingerprint check
debug1: Server host key: ecdsa-sha2-nistp256 SHA256:...

# Authentication methods the server offers
debug1: Authentications that can continue: publickey,password

# Key being tried
debug1: Offering public key: /home/user/.ssh/id_ed25519 ED25519 SHA256:...

# Why authentication failed
debug1: Authentications that can continue: publickey
debug1: No more authentication methods to try.

# If permission denied
debug3: authmethod_lookup publickey
debug3: remaining preferred: keyboard-interactive,password

Common -vvv findings:

  • "no such identity" — The private key file path in your config is wrong
  • "Server refused our key" — Key is not in authorized_keys, or file permissions are wrong
  • "authentications that can continue: publickey" — Password auth is disabled; only key works
  • Hangs at "expecting SSH2_MSG_SERVICE_ACCEPT" — Firewall is dropping packets mid-connection