ssh: connect to host server port 22: Connection refused means the SSH daemon is not listening on that port on that host. The cause is one of seven things: sshd is not running, the firewall is blocking, the port is non-standard, the host does not resolve, IPv6 vs IPv4 mismatch, sshd is bound to a specific interface, or the wrong IP. The team that walks through this checklist resolves the issue in under five minutes.
Table of contents
- Is sshd running?
- Is the firewall open?
- Is the port correct?
- Does the host resolve?
- IPv6 vs IPv4 mismatch
- sshd bound to a specific interface
- The wrong IP entirely
- FAQ
Is sshd running?
First check: is the SSH daemon even running on the server?
sudo systemctl status ssh
# or
sudo systemctl status sshd
The expected output: active (running). The team that sees inactive (dead) or failed needs to start the service:
sudo systemctl start ssh
sudo systemctl enable ssh # so it starts at boot
If the service fails to start, check sudo journalctl -u ssh -e for the error. Common causes: bad sshd_config syntax, missing host keys, missing /var/run/sshd directory.
Is the firewall open?
The service can be running and still unreachable if the firewall blocks the port:
# ufw (Ubuntu)
sudo ufw status
sudo ufw allow 22/tcp
# firewalld (RHEL family)
sudo firewall-cmd --list-all
sudo firewall-cmd --add-service=ssh --permanent
sudo firewall-cmd --reload
# iptables (legacy)
sudo iptables -L -n
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
The team that runs the server in a cloud provider (AWS, GCP, Azure) has TWO firewalls - the OS one and the cloud security group. Both need to allow port 22. The team that opens the OS firewall but forgets the security group is debugging in the wrong place.
Is the port correct?
If sshd_config has been changed to a non-default port, the client needs to know:
# Default
ssh user@server
# Non-default
ssh -p 2222 user@server
The server-side check:
sudo ss -tlnp | grep ssh
# or
sudo netstat -tlnp | grep ssh
The output shows what port(s) sshd is listening on. The team that sees *:22 is fine. The team that sees *:2222 knows to use -p 2222 on the client.
Does the host resolve?
The IP might be wrong:
# Check what client thinks
nslookup server.example.com
# or
dig server.example.com
# or
getent hosts server.example.com
The team that sees the expected IP is fine. The team that sees NXDOMAIN has a DNS problem - either the hostname is wrong, the DNS server is wrong, or the record does not exist.
# Try the IP directly
ssh [email protected]
If the IP works but the hostname does not, it is DNS. The team that bypasses DNS with /etc/hosts entries is fine temporarily; the long-term fix is to update the DNS record.
IPv6 vs IPv4 mismatch
The server might be listening on IPv6 only, or IPv4 only:
sudo ss -tlnp | grep ssh
If the output shows [::]:22 (IPv6), the client needs to connect over IPv6 or the server needs an IPv4 listener too. If the output shows 0.0.0.0:22 (IPv4), the server is listening on IPv4.
The team that has AddressFamily inet in sshd_config restricts to IPv4. The team that has AddressFamily inet6 restricts to IPv6. The team that has AddressFamily any listens on both. Pick the right setting for the network setup.
sshd bound to a specific interface
sshd_config can bind to a specific IP:
ListenAddress 192.168.1.10
ListenAddress 2001:db8::1
That tells sshd to listen only on those interfaces. If the client connects from a different network (e.g., the public internet) and the server has ListenAddress 127.0.0.1, the connection is refused.
The team that uses this for security (only listen on internal interface) needs to make sure clients can reach the bound interface.
The wrong IP entirely
The client might be connecting to the wrong server:
# Check the route
traceroute server.example.com
# or
mtr server.example.com
If the route ends at an unexpected IP, the team has a network problem. The team that has multiple servers with similar names (web1, web2, web3) sometimes gets the routing wrong. The fix is to check the actual IP.
FAQ
How do I check if a port is open from the client side?
nc -zv server 22 (netcat) or Test-NetConnection -Port 22 server (PowerShell). If it shows succeeded or open, the port is reachable. If it shows refused or timed out, the port is not reachable.
What is the difference between refused and timed out?
Refused = the server responded with TCP RST (port closed). Timed out = no response (firewall dropped the packet, or the server is down). The team that sees timed out should check the firewall. The team that sees refused should check the service.
Can I see SSH logs on the server?
Yes: sudo journalctl -u ssh -e (systemd) or sudo tail -f /var/log/auth.log (Debian/Ubuntu) or /var/log/secure (RHEL family). The team that monitors these sees failed attempts and successful logins.
Does SSH work over IPv6?
Yes. SSH works over both IPv4 and IPv6. The team that sees Connection refused on IPv6 might need to add AddressFamily any to sshd_config and check that the firewall allows IPv6.
What if the connection is slow to establish?
Add -o IPQoS=lowdelay throughput and -o ServerAliveInterval=60. The team that has a slow first connection often has a DNS reverse-lookup issue - UseDNS no in sshd_config skips the reverse lookup that causes the delay.
If you are sizing the infrastructure for the kind of project this post covers, the RunxBuild hosting calculator is the right place to model the line items. The compute, the memory, the storage, the bandwidth, the database - each one is a separate number, and the team’s mental model for the platform is the sum of those numbers. The RunxBuild dashboard is where the team sees the actual usage in one place.
Useful related references: