Ssh Connection Refused Port 22: The Complete 2026 Guide

Ssh Connection Refused Port 22: The Complete 2026 Guide

Ssh connection refused on port 22 usually means the SSH daemon isn’t running, or a firewall is blocking inbound traffic. Check if sshd is active via Systemd. Verify iptables or UFW rules. Test TCP connectivity with Netcat. Ensure your public key authentication config in sshd_config is not rejecting your IP. Fixing this requires isolating whether the issue is service-level or network-level before tweaking advanced security policies.

How Does Port 22 Refusal Differ from Timeouts?

Most engineers mix these up. In my experience supporting legacy Linux infra, the error message tells you exactly where to look. If you see “Connection refused,” the packet reached the host. The OS said “no.” The process listening on that port might be dead, or a local firewall rule explicitly dropped it.

If you see “Connection timed out,” the packet never got answered. The host is likely down, or an external firewall dropped the packet silently. No response. Just silence. For this guide, we focus strictly on the “refused” state. It implies the server is alive but rejecting your doorbell. Treat timeouts as a separate network outage problem, not an SSH configuration issue.

Why Does sshd Fail to Listen on Port 22?

The SSH daemon depends on the system’s network stack and configuration files. A typo in one six-line block can kill the entire service. When systemd stops sshd, port 22 closes immediately. Clients receive the RST (Reset) packet instantly.

Common culprits I see in production support tickets:

  • Corrupted host keys: If /etc/ssh/ssh_host_* files are missing or corrupt, sshd refuses to start. This often happens after a bad disk write or a partial file copy.
  • AddressFamily mismatch: Setting AddressFamily inet while your server only has IPv6 configured. The daemon tries to bind to a non-existent socket.
  • ListenAddress conflicts: Specifying an IP address that isn’t assigned to your current interface. The kernel rejects the bind request.

Check the logs first. Always. Run journalctl -u ssh -n 50 to see the last 50 lines of the service log. Look for “failed to load host key” or “address already in use.” If the log shows a clean startup but the port is closed, the issue is likely a firewall rule overriding the socket state.

What Firewall Rules Block Incoming SSH Traffic?

Firewalls operate in layers. Even if sshd is running, iptables can block the traffic before it hits the socket. This is where many “refused” errors actually originate. The host is up, the service is up, but the gate is locked.

On Debian and Ubuntu systems, UFW manages these rules. Check your status immediately. Run sudo ufw status verbose. Look for line 22 (or 322 if you moved it). It should say ALLOW. If it says REJECT or DROP, you have found your problem. Add the rule with sudo ufw allow 22/tcp.

On CentOS or RHEL, firewalld handles this differently. You need sudo firewall-cmd --list-ports. If 22/tcp isn’t there, add it with sudo firewall-cmd --add-port=22/tcp --permanent and reload. I’ve seen cases where a reboot reset the temporary rules, causing sudden outages. Always make rules permanent if you want them to survive a power cycle.

How Do You Verify Service Status Directly?

Assuming the firewall is clean, we need to confirm the daemon is actually bound to the interface. Use Netcat for a raw TCP check. This bypasses the SSH handshake entirely. It just tests if the port is open.

Run this from your local machine:

nc -zv your_server_ip 22

If you get “Connection succeeded,” the port is open. The issue is now strictly within the SSH protocol negotiation, not the connectivity layer. If you get “Connection refused,” the port is closed despite your beliefs. There is a discrepancy between what you think is running and what is actually bound to the network card.

On the server, verify the binding: ss -tlnp | grep :22. This shows all listening TCP sockets. If sshd appears in the process column, it is listening. If nothing appears, the service isn’t running. Start it with sudo systemctl start ssh. Check the status again. If it fails, read the error message in the output. It is specific. Trust it.

Why Would sshd Ignore Your Authentication Attempts?

Sometimes the connection establishes, but the protocol handshake fails. Or, you get refused because sshd is configured to reject unknown IPs before even offering the password prompt. This is a security feature that becomes a usability nightmare if misconfigured.

Check /etc/ssh/sshd_config. Look for AllowUsers or AllowGroups. If these lines exist, they override default access policies. If your username isn’t in that list, the connection is rejected instantly. I recall a ticket where a developer added AllowUsers deploy but forgot to add his own account to the deploy group. He couldn’t log in for two hours. Not fun.

Also inspect HostbasedAuthentication and PubkeyAuthentication. If both are set to no, and you don’t have a password entry, you are locked out. In 2026, disabling password authentication is standard best practice, per OWASP guidelines on secure authentication. But you must ensure your key-based auth is working *before* you flip the switch. Test with a fallback SSH session first.

How Do You Diagnose AddressFamily and Network Interface Issues?

Modern servers often have multiple network interfaces. The ListenAddress directive in sshd_config tells the daemon where to bind. If you specify ListenAddress 192.168.1.10 but your server is currently at 10.0.0.5, the bind fails. The service crashes or fails to start.

Check your actual IP with ip addr show. Compare it to your sshd_config. If they differ, remove the ListenAddress line entirely. By default, sshd listens on all available interfaces (0.0.0.0 or ::). This is usually what you want. Explicit binding is only necessary for complex multi-homed server setups.

Also, check AddressFamily. If set to inet (IPv4 only) and you are connecting via IPv6, you get refused. If set to ipv6 and you lack IPv6 support, same result. The safest setting is any or simply commenting the line out to let the system decide. Review your config file for implicit assumptions about your network state.

What Are the Advanced Debugging Steps for Persistent Errors?

If standard checks fail, enable verbose logging. This increases file size and CPU usage slightly, but it captures every detail. In production, use a temporary file instead of growing /var/log/auth.log indefinitely.

Run sudo sshd -d -p 2222. This creates a debug instance on port 2222. It runs in the foreground. All logs appear in your terminal. Now, connect to port 2222 from your client with ssh -v user@ip -p 2222. The -v flag enables verbose client output. You will see exactly where the handshake breaks. Is it at key exchange? Is it at user authentication? The logs side-by-side will reveal the exact rejection reason.

Common hidden issues found in debug mode:

  • Mismatched HMAC algorithms between client and server.
  • Client offering a deprecated cipher that the server rejects.
  • SELinux or AppArmor blocking file access for the key pair.

Once identified, update your sshd_config to match the supported crypto parameters. Restart the service. Verify the connection. Don’t forget to kill the debug instance on 2222 when you are done.

How Can You Prevent Future SSH Connection Failures?

Prevention beats recovery. Build a monitoring habit. Use Zabbix or Prometheus to monitor port 22 availability. If the port closes, alert immediately. Don’t wait for a user to complain. You lose an hour of downtime before you even know something is wrong.

Manage changes through configuration management tools. Ansible or Chef scripts ensure sshd_config remains consistent across your fleet. Manual edits drift. Drift causes outages. I’ve seen servers where someone manually commented out a line, forgot to document it, and caused a cascade of failures months later. Automate where possible.

Keep your SSH keys organized. Use dedicated key pairs per admin. Revoke compromised keys immediately. Rotating keys every 90 days reduces the blast radius of a leak. Also, consider moving SSH to a non-standard port *after* securing it properly. This lowers low-effort scanning noise, but it does not replace hardening. Security through obscurity is weak. Hardening is strong.

Familiarize yourself with your server’s recovery process. If remote access fails, do you have console access via your hosting provider? If the answer is no, you have a single point of failure. Learn how to access the IPMI or vKVM interface of your server. It is boring practice until the day you need it. Then it is a lifesaver.

Related Guides on abdulabror.com

Frequently Asked Questions

Why did my SSH stop working after a reboot?

Usually, temporary firewall rules were lost. UFW and firewalld often reset to default deny if not saved as permanent. Also, check if the sshd service failed to start due to a corrupted config file edited before the reboot. Check journalctl for startup errors.

Can I use another port to test connectivity?

Yes. Change Port 22 to Port 2222 in sshd_config, restart the service, and test. If 2222 works, the issue is specific to port 22 restrictions or a conflicting application using port 22. This isolates the variable effectively.

Does Cloudflare block SSH traffic by default?

Yes. Cloudflare’s standard proxy does not support raw TCP traffic for SSH. You must use “Grey Cloud” (DNS only) mode or enable Flexible SSH (if available on your plan) to route port 22 traffic directly to your origin server. Proxying SSH causes handshake failures.

How do I check if SELinux is blocking SSH?

Run sestatus to check if SELinux is enforcing. If it is, check the audit log for DENIED messages related to sshd_t. Use ausearch -m avc -ts recent to see recent denials. Fix the context with restorecon or adjust the policy.

Leave A Comment

Need help with WordPress or hosting?

Based in Bali, Indonesia

Providing technical hosting support and WordPress services to clients worldwide. Remote-friendly, reliable, and always focused on practical solutions.

Samping work with me