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
| Cause | How it shows up |
|---|---|
| MaxStartups limit hit | Works sometimes, fails during bursts of bots or scripts |
| fail2ban, CSF or DenyHosts ban | Fails only from your IP; works from mobile data |
| TCP wrappers (hosts.deny) | Fails for everyone except whitelisted IPs |
| sshd crashed or config broken | Fails for everyone, even from the VPS console |
| Out of memory or process limits | sshd can't fork a child; slow, flaky VPS |
| Middlebox or ISP interference | Fails 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
MaxStartupsraised if your VPS is public-facing on port 22. - Always test config changes with
sshd -tand 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.
