When ssh fails, the error message already tells you at which stage the connection broke: the network, the SSH service, the key exchange or authentication. In this tutorial you will work through those stages in order, starting from your local machine and then, if needed, from the server's web console. The server-side commands target Ubuntu 24.04 LTS; the client-side commands work with OpenSSH on Linux, macOS and Windows 10/11.
Prerequisites
- A Linux or macOS workstation, or Windows with the built-in OpenSSH client.
- The server's IP address (
your_server_ip), the SSH port (22 unless you changed it) and the user you log in as (your_user). - For the server-side steps: a way to reach the server without SSH, such as the web-based console in your provider's control panel. A CubePath VPS running Ubuntu 24.04 is assumed in the examples.
Step 1 - Reading the error message
Run the connection once and read the last line carefully. Each common error points to a different layer:
| Error | Most likely cause | Go to |
|---|---|---|
Connection timed out | Server down, wrong IP, or a firewall silently dropping port 22 | Step 2 |
No route to host / Network is unreachable | Routing problem or a firewall rejecting the traffic | Step 2 |
Connection refused | Nothing listening on that port: sshd stopped or on another port | Step 2, then Step 5 |
Connection closed by ... port 22 right after connecting | fail2ban, MaxStartups or a banned IP | Step 7 |
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! | Server reinstalled or its host keys changed | Step 4 |
Permission denied (publickey) | Wrong key, wrong user, or bad permissions on the server | Steps 3 and 6 |
Too many authentication failures | Your agent offers too many keys before the right one | Step 3 |
Step 2 - Checking network reachability and the SSH port
First confirm that the server answers at all. Many servers drop ICMP, so a failed ping is a hint, not proof:
ping -c 4 your_server_ip
The decisive test is whether the TCP port accepts connections. Use nc (preinstalled on Ubuntu and macOS):
nc -vz -w 5 your_server_ip 22
Connection to your_server_ip 22 port [tcp/ssh] succeeded!
Interpret the result:
- succeeded: the network and the port are fine; the problem is in SSH itself. Continue with Step 3.
- Connection refused: the host is up, but nothing listens on that port. Check that you are using the right port, then Step 5.
- timed out: packets are being dropped. Either the server is down, the IP is wrong, or a firewall (UFW on the server, a network firewall, or your office network) is blocking the port.
If you connect by hostname, make sure it resolves to the IP you expect:
dig +short your_domain
To see where packets stop on the way, use mtr (install it with sudo apt install mtr-tiny on Ubuntu or brew install mtr on macOS):
mtr -rwc 20 your_server_ip
Loss that starts at one hop and continues to the end points to that network. Loss only at the last hop with a working ping usually means the server is up and a firewall is filtering port 22.
Tipto rule out your own network, try the same
nctest from a different connection, such as a phone hotspot. Some corporate and public Wi-Fi networks block outbound port 22.
Step 3 - Debugging the client with verbose output
When the port is open but login fails, run SSH in verbose mode. Add up to three v for more detail:
ssh -vvv your_user@your_server_ip
The lines worth looking for are:
debug1: Connecting to your_server_ip [your_server_ip] port 22.
debug1: Connection established.
debug1: Remote protocol version 2.0, remote software version OpenSSH_9.6p1 Ubuntu-3ubuntu13
debug1: Authentications that can continue: publickey
debug1: Offering public key: /home/you/.ssh/id_ed25519 ED25519 SHA256:...
debug1: Authentications that can continue: publickey
debug1: No more authentication methods to try.
your_user@your_server_ip: Permission denied (publickey).
This output tells you three useful things: the connection and key exchange worked, the server only accepts publickey (passwords are disabled), and the key your client offered was rejected. Either it is the wrong key, or the matching public key is not in the server user's ~/.ssh/authorized_keys.
Check which settings your client actually applies for this host, including anything from ~/.ssh/config:
ssh -G your_server_ip | grep -Ei '^(user|port|hostname|identityfile) '
If you have several keys loaded in your agent, the server may cut you off with Too many authentication failures before the right key is tried. Force a single key:
ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 your_user@your_server_ip
On the client, the private key must be readable only by you, or SSH refuses to use it:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
To test whether password login is possible (only if it is enabled on the server):
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no your_user@your_server_ip
Step 4 - Fixing host key verification errors
SSH stores each server's host key in ~/.ssh/known_hosts. If the server was reinstalled or rebuilt, its key changes and the client refuses to connect:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Only remove the old key when you know why it changed. If you did not reinstall the server, verify the fingerprint first from the server console:
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
If it matches the fingerprint shown when you reconnect, remove the stale entry on your workstation:
ssh-keygen -R your_server_ip
Connect again and accept the new fingerprint after comparing it.
Warningdo not work around this error with
StrictHostKeyChecking=no. A changed key you cannot explain may mean the traffic is being intercepted.
Step 5 - Checking the SSH service from the console
If the port is refused or filtered, log in through the web console and inspect the server directly. On Ubuntu 24.04, SSH is started through systemd socket activation, so check both the socket and the service:
sudo systemctl status ssh.socket ssh.service
Confirm what is listening and on which port:
sudo ss -tlnp 'sport = :22'
LISTEN 0 4096 0.0.0.0:22 0.0.0.0:* users:(("systemd",pid=1,fd=58))
LISTEN 0 4096 [::]:22 [::]:* users:(("systemd",pid=1,fd=59))
With socket activation the listener is owned by systemd, which is expected. If nothing listens, validate the configuration before restarting, since a syntax error prevents sshd from starting:
sudo sshd -t
No output means the configuration is valid. Then start it again:
sudo systemctl restart ssh.socket
sudo systemctl restart ssh.service
Review the recent log for the reason it failed:
sudo journalctl -u ssh -n 50 --no-pager
Noteon Ubuntu 24.04, a
Portchanged in/etc/ssh/sshd_configonly takes effect aftersudo systemctl daemon-reloadfollowed bysudo systemctl restart ssh.socket, because the socket unit reads it at boot. If you changed the port and still see:22, that is the reason.
Next, check the firewall. With UFW active, SSH must be explicitly allowed:
sudo ufw status verbose
If the rule is missing, add it (use your custom port instead of OpenSSH if you changed it, for example sudo ufw allow 2222/tcp):
sudo ufw allow OpenSSH
Step 6 - Checking authentication on the server
The server log states exactly why an authentication was rejected. Watch it while you try to connect from your workstation:
sudo journalctl -u ssh -f
Typical messages and their meaning:
Invalid user admin from 203.0.113.10: the username does not exist on the server.Authentication refused: bad ownership or modes for directory /home/your_user: permissions are too open.Connection closed by authenticating user your_user ... [preauth]: the offered key did not match any entry inauthorized_keys.
Print the effective server settings that matter for login. Ubuntu cloud images add files under /etc/ssh/sshd_config.d/, which can override the main file:
sudo sshd -T | grep -Ei '^(port|permitrootlogin|passwordauthentication|pubkeyauthentication|allowusers|allowgroups) '
port 22
permitrootlogin without-password
pubkeyauthentication yes
passwordauthentication no
sshd is strict about permissions. The home directory must not be writable by others, and .ssh and authorized_keys must belong to the user:
sudo chown -R your_user:your_user /home/your_user/.ssh
sudo chmod 755 /home/your_user
sudo chmod 700 /home/your_user/.ssh
sudo chmod 600 /home/your_user/.ssh/authorized_keys
Finally, confirm the public key from your workstation is present. Print it locally with cat ~/.ssh/id_ed25519.pub and compare it with:
sudo cat /home/your_user/.ssh/authorized_keys
Each key must be on a single line. Keys pasted through a console often get broken across lines; fix that and try again.
Step 7 - Checking whether your IP is banned
If connections are accepted and then closed immediately, or suddenly time out after several failed attempts, your IP may have been banned by fail2ban, if it is installed. Check the SSH jail:
sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
| |- Currently failed: 0
| `- Total failed: 14
`- Actions
|- Currently banned: 1
`- Banned IP list: 198.51.100.23
If your public IP is listed, unban it:
sudo fail2ban-client set sshd unbanip 198.51.100.23
Also review any AllowUsers or AllowGroups lines shown by sshd -T in the previous step: a user not listed there is rejected even with a valid key.
Conclusion
You checked SSH layer by layer: network reachability, the listening port, the client's keys and host key cache, the sshd service and its configuration, and bans. Working through the stages in this order narrows almost any SSH failure down to one cause in a few minutes. As next steps, consider setting up key-only authentication and fail2ban, and keep console access details at hand so a broken sshd_config never locks you out completely.
