How to fix ssh connection refused error on a VPS
An SSH "Connection refused" error means your client can't establish a TCP connection to the server at all — the port is closed, the service isn't running, or something is blocking the traffic. Here's how to systematically diagnose and fix it.
1. Verify the SSH Service Is Actually Running
The most common cause is that the SSH daemon (sshd) has stopped or failed to start. Log into your VPS via your provider's web console (most VPS providers offer a browser-based emergency console for exactly this situation), then run:
sudo systemctl status sshd
If the service is stopped or failed, you'll see output like Active: inactive (dead) or Active: failed. Restart it with:
sudo systemctl restart sshd
Then check status again to confirm it's running. On Ubuntu and Debian, the service may be named ssh instead of sshd:
sudo systemctl restart ssh
On CentOS, AlmaLinux, or RHEL-based systems, the service is named sshd and the command above applies as written.
2. Confirm Which Port SSH Is Listening On
If the service is running but you're still getting refused, SSH may have been configured to listen on a non-standard port. Check the current configuration:
sudo grep -i port /etc/ssh/sshd_config
If the output shows something like Port 2222 instead of the default Port 22, you need to connect using that port explicitly:
ssh -p 2222 user@your-server-ip
You can also verify what ports sshd is actually bound to right now:
sudo ss -tlnp | grep sshd
The output will show the local address and port (e.g., 0.0.0.0:22 or :::22). If nothing shows up, the daemon isn't listening — go back to Step 1.
3. Check Your Firewall Rules
A running SSH service can still be unreachable if a firewall is dropping traffic before it arrives. Check ufw first on Ubuntu/Debian:
sudo ufw status
If the output shows Status: active and port 22 (or your custom SSH port) isn't listed as allowed, add it:
sudo ufw allow 22/tcp
sudo ufw reload
On CentOS/AlmaLinux using firewalld:
sudo firewall-cmd --list-all
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload
If you're using raw iptables, check the current rules:
sudo iptables -L INPUT -n --line-numbers
Look for a DROP or REJECT rule targeting port 22 that might be overriding an ACCEPT rule. Rule order matters — a DROP higher in the chain will block traffic even if an ACCEPT exists below it.
4. Check Your VPS Provider's Network-Level Firewall
This is a common gotcha: many VPS control panels include a separate cloud firewall or security group that sits outside the operating system entirely. Even if ufw allows port 22, a network-level rule blocking it will cause "Connection refused" (or more often, a timeout). Log into your hosting control panel and verify that port 22 TCP inbound is permitted for your server's IP.
5. Look at SSH Logs for the Root Cause
If the service keeps failing to start, the logs will tell you why:
sudo journalctl -u sshd -n 50 --no-pager
Common log errors and what they mean:
- "Address already in use" — Another process is bound to port 22. Find it with
sudo ss -tlnp | grep :22and stop the conflicting service. - "Missing privilege separation directory: /run/sshd" — The directory was deleted. Recreate it:
sudo mkdir -p /run/sshd && sudo chmod 0755 /run/sshd - "No hostkeys available" — SSH host keys are missing. Regenerate them:
sudo ssh-keygen -A
6. Test Connectivity From Outside Before Assuming It's Fixed
After making changes, don't just retry your SSH client — use a port check first to confirm the port is actually reachable from the outside world:
nc -zv your-server-ip 22
A successful response looks like Connection to your-server-ip 22 port [tcp/ssh] succeeded!. If it still fails from outside but works locally on the server, the issue is almost certainly a firewall — either the OS firewall or the network-level one from your provider.
Quick Reference Checklist
- Is
sshdrunning? →systemctl status sshd - Is it on the expected port? →
ss -tlnp | grep sshd - Is
ufworfirewalldblocking it? → check and allow the port - Is there a cloud/panel-level firewall blocking it? → check your provider's control panel
- What do the logs say? →
journalctl -u sshd -n 50