You type ssh root@your-vps-ip, and instead of a password prompt you get this: kex_exchange_identification: Connection closed by remote host. Sometimes it's Connection reset by peer or Connection closed by 203.0.113.10 port 22. The server is clearly up, because it answered, then it hung up on you before you could even authenticate. Here's how we track this down on SkyServer VPS plans.

What the error actually means

SSH connections start with a short handshake: both sides swap version banners, then negotiate encryption (the "key exchange", or KEX). This error says the TCP connection was accepted, but the server closed it before that handshake finished. So it's not a wrong password, not a bad key, and not a firewall silently dropping packets (that would give you a timeout). Something on the server deliberately refused you after the connection opened.

The usual causes

CauseHow it shows up
MaxStartups limit hitWorks sometimes, fails during bursts of bots or scripts
fail2ban, CSF or DenyHosts banFails only from your IP; works from mobile data
TCP wrappers (hosts.deny)Fails for everyone except whitelisted IPs
sshd crashed or config brokenFails for everyone, even from the VPS console
Out of memory or process limitssshd can't fork a child; slow, flaky VPS
Middlebox or ISP interferenceFails on one network only

Step 1: Get the real reason with verbose output

Run the client in verbose mode so you can see exactly where it dies:

ssh -vvv root@your-vps-ip

If you see the line Connection established followed by an immediate close, the server is rejecting you. If it hangs at "Connecting", that's a different problem (network or firewall), and you'd want to check ports instead.

Step 2: Test from a different network

Switch your laptop to your phone's hotspot and try again. If it works there, your own IP is being blocked on the server, or your home/office network is interfering. That single test saves a lot of guessing.

Step 3: Log in through the VPS console and read the logs

Use the console in your SkyServer client area (it doesn't depend on SSH). Then check what sshd said about your attempt:

journalctl -u ssh -n 100 --no-pager      # Debian/Ubuntu
journalctl -u sshd -n 100 --no-pager     # AlmaLinux/Rocky
tail -n 100 /var/log/auth.log            # Debian/Ubuntu
tail -n 100 /var/log/secure              # RHEL family

Look for lines such as drop connection #... from [ip]:port on [ip]:22 past MaxStartups, refused connect from (TCP wrappers) or Failed password bursts followed by a ban.

Fix A: MaxStartups is too low

sshd allows only a limited number of unauthenticated connections at once. The default is 10:30:100, meaning that after 10 half-open connections it starts randomly dropping 30% of new ones, and refuses everything at 100. Internet-wide bot scans can push you over that easily.

sudo nano /etc/ssh/sshd_config
# add or change:
MaxStartups 30:30:100
LoginGraceTime 30
sudo sshd -t && sudo systemctl reload sshd

Always run sshd -t first. It checks the config syntax, so a typo doesn't lock you out. A better long-term answer is to reduce the bot noise: move SSH off port 22 or restrict it to known IPs in your firewall.

Fix B: Your IP got banned

Too many failed logins, even from a script you forgot about, will get you blocked. Check and unban:

# fail2ban
sudo fail2ban-client status sshd
sudo fail2ban-client set sshd unbanip YOUR.IP.ADDR.ESS

# CSF (cPanel VPS)
csf -g YOUR.IP.ADDR.ESS
csf -dr YOUR.IP.ADDR.ESS
csf -a YOUR.IP.ADDR.ESS "my office"

Add your static IP to the ignore list (ignoreip in /etc/fail2ban/jail.local) so it doesn't happen again. We cover that in our fail2ban unban guide.

Fix C: TCP wrappers or an AllowUsers rule

On older systems, check these two files:

cat /etc/hosts.deny
cat /etc/hosts.allow
grep -E "AllowUsers|AllowGroups|DenyUsers" /etc/ssh/sshd_config

If hosts.deny contains sshd: ALL and your IP isn't in hosts.allow, that's your culprit. Note that the AllowUsers restrictions normally produce a "Permission denied" after authentication, not a KEX error, but it's worth ruling out.

Fix D: sshd is broken or the server is starved

systemctl status ssh      # or sshd
sudo sshd -t
free -m
dmesg | grep -i "out of memory"

If sshd isn't running, start it and read the error from sshd -t. If the VPS is nearly out of RAM, the kernel may kill sshd children. Add swap or trim memory-hungry services; see our OOM killer guide.

Fix E: Your network is the problem

If the hotspot test worked and the server shows nothing in its logs, the connection never reached sshd properly. Some corporate firewalls and ISPs reset long-lived or "unusual" port 22 traffic. Try a different port (add Port 2222 to sshd_config, open it in your firewall before reloading) or connect through a VPN.

Prevention

  • Use SSH keys and disable password logins so bots can't rack up failures that trigger bans.
  • Whitelist your own static IP in fail2ban or CSF.
  • Keep MaxStartups raised if your VPS is public-facing on port 22.
  • Always test config changes with sshd -t and keep a second session open while reloading.
  • Know where your VPS console lives before you need it.

Frequently Asked Questions

Is "kex_exchange_identification" a sign I've been hacked?

Usually not. It most often comes from MaxStartups throttling during bot scans or from a ban. Still, check last and your auth log for logins you don't recognise.

Why does it work sometimes and fail other times?

That pattern points to MaxStartups random-drop behaviour or an unstable network path. Raise the limit and compare results from another network.

Can I fix this without console access?

Not on the server side, since you need a shell to edit config or unban an IP. If SSH is your only door, use the VPS console or open a support ticket and we'll look at it with you.

Does changing the SSH port help?

It cuts down bot traffic a lot, which often removes the MaxStartups problem. It isn't a substitute for keys and a firewall, though.