How to fix kex_exchange_identification: Connection closed by remote host in SSH

SSHINTERMEDIATEMEDIUMUpdated May 28, 2026ยท 1,737 views

SSH fails during the key-exchange identification handshake because the server closes the TCP connection before negotiation finishes. It's a connectivity or server-side issue (fail2ban, MaxStartups, firewall), not authentication.

Quick fix

Fixes kex_exchange_identification: Connection closed by remote host

# Check fail2ban status for the sshd jail (lists currently banned IPs)
sudo fail2ban-client status sshd

# Check TCP wrappers
sudo cat /etc/hosts.deny
sudo cat /etc/hosts.allow

# Check iptables/nftables for drop rules on the SSH port
sudo iptables -L -n | grep -E 'ssh|:22'
sudo nft list ruleset 2>/dev/null | grep -E 'ssh|22'
  1. Check if your IP is blocked by fail2ban or TCP wrappers
  2. Connect with verbose output to confirm where it fails
  3. Check SSH server logs for the root cause
  4. Verify sshd is running and its config is valid
ssh โ€” error
# Check fail2ban status for the sshd jail (lists currently banned IPs)
sudo fail2ban-client status sshd
# Check TCP wrappers
sudo cat /etc/hosts.deny
sudo cat /etc/hosts.allow
# Check iptables/nftables for drop rules on the SSH port
sudo iptables -L -n | grep -E 'ssh|:22'
sudo nft list ruleset 2>/dev/null | grep -E 'ssh|22'
kex_exchange_identification: Connection closed by remote host

What this error means

An SSH connection happens in phases. The very first phase is the protocol/version identification and key exchange (KEX) banner exchange, where the client and server announce themselves and begin negotiating encryption. The `kex_exchange_identification: Connection closed by remote host` error means the server (or something in front of it) dropped the TCP connection before it ever sent its identification string. Because this happens before any algorithm negotiation, key verification, or authentication, it is almost always a connectivity or server-side gatekeeping problem rather than a credential problem. The most common culprits are intrusion-prevention tools that banned your IP (fail2ban, DenyHosts), the SSH daemon refusing new connections because it hit its `MaxStartups` limit, TCP wrappers (`/etc/hosts.deny`), or a firewall/middlebox resetting the connection.

Typical symptoms

  • SSH connection fails immediately with 'kex_exchange_identification: Connection closed by remote host'
  • The error appears during the key exchange / identification phase, not during password or key authentication
  • Running ssh -vvv shows the connection closing before the server sends its SSH version banner
  • Some SSH clients or networks can connect while others cannot from the same source
  • The issue is intermittent or only happens from certain networks or IP addresses
  • Reconnecting after a short wait sometimes succeeds (consistent with rate limiting or temporary bans)

Common causes

  1. Your IP has been blocked by fail2ban, DenyHosts, or a similar intrusion-prevention tool on the server
  2. The SSH daemon has hit its MaxStartups limit and is refusing new unauthenticated connections
  3. A firewall on the client, server, or network path is resetting or dropping the connection
  4. The server is overloaded or actively under a brute-force attack, exhausting connection slots
  5. Your IP is listed in /etc/hosts.deny or absent from /etc/hosts.allow (TCP wrappers)
  6. Network problems such as packet loss, high latency, or MTU/fragmentation issues break the handshake
  7. The SSH daemon (sshd) crashed, is not running, or failed to load its host keys
  8. A wrapper, port-knocking rule, or non-SSH service is occupying the SSH port and closing connections

How to fix "kex_exchange_identification: Connection closed by remote host"

1Check if your IP is blocked by fail2ban or TCP wrappers

On the server, the most common cause is that an intrusion-prevention tool banned your IP. Check for it:

bash
# Check fail2ban status for the sshd jail (lists currently banned IPs)
sudo fail2ban-client status sshd

# Check TCP wrappers
sudo cat /etc/hosts.deny
sudo cat /etc/hosts.allow

# Check iptables/nftables for drop rules on the SSH port
sudo iptables -L -n | grep -E 'ssh|:22'
sudo nft list ruleset 2>/dev/null | grep -E 'ssh|22'

If your IP is banned by fail2ban, unban it (replace <your-ip> with your actual address):

bash
sudo fail2ban-client set sshd unbanip <your-ip>
2Connect with verbose output to confirm where it fails

On your client machine, use maximum verbosity to confirm the failure happens at identification, before any banner is received:

bash
ssh -vvv user@hostname

Look for the last successful step. With this error you will typically see the TCP connection established, then it closes before a line like debug1: Remote protocol version ... appears. That confirms the server closed the connection before sending its SSH banner, pointing to a server-side gate (ban, MaxStartups, wrapper) rather than authentication.

3Check SSH server logs for the root cause

On the server, inspect the SSH daemon logs to see why it closed the connection:

bash
# systemd-based systems
sudo journalctl -u ssh -u sshd -n 50 --no-pager

# syslog-based systems (Debian/Ubuntu vs RHEL/CentOS)
sudo tail -n 50 /var/log/auth.log
sudo tail -n 50 /var/log/secure

Look for messages such as:
- error: beginning MaxStartups throttling / drop connection #N
- refused connect from (TCP wrappers)
- Unable to load host key
- fatal: ... too many connections

These point directly at the cause.

4Verify sshd is running and its config is valid

On the server, make sure the daemon is actually running and that no broken config is causing it to reject or crash on connections:

bash
# Check if sshd is running
sudo systemctl status ssh sshd

# Validate the configuration WITHOUT restarting
sudo sshd -t

# If config is valid and a restart is warranted, reload/restart
sudo systemctl restart ssh sshd

The -t flag tests the configuration and prints any syntax errors. Fix reported errors before restarting, otherwise sshd may fail to come back up.

5Raise MaxStartups if the server is dropping connections under load

If the logs show MaxStartups throttling, the daemon is dropping new unauthenticated connections because too many are pending. On the server, review the setting:

bash
sudo grep -i maxstartups /etc/ssh/sshd_config

The default is 10:30:100 (start randomly dropping at 10 pending connections, 30% drop rate, hard cap at 100). If you have legitimate high concurrency, raise it:

bash
# Example: start throttling at 50, hard cap at 200
MaxStartups 50:30:200

Then validate and restart:

bash
sudo sshd -t
sudo systemctl restart ssh sshd

Note: raising MaxStartups increases exposure during a brute-force attack, so prefer fixing the underlying load or ban source where possible.

6Check SSH host keys exist and have correct permissions

If the logs show Unable to load host key, sshd may close connections because it cannot present a host key. On the server:

bash
# Inspect host keys
sudo ls -la /etc/ssh/ssh_host_*

# Expected permissions:
#   Private keys: 600 (-rw-------)
#   Public keys:  644 (-rw-r--r--)

# Fix permissions if needed
sudo chmod 600 /etc/ssh/ssh_host_*_key
sudo chmod 644 /etc/ssh/ssh_host_*_key.pub

If host keys are missing or corrupted, regenerate them and restart:

bash
sudo ssh-keygen -A
sudo systemctl restart ssh sshd
7Rule out network, firewall, and MTU problems

If the server side looks healthy, confirm the connection isn't being reset or fragmented in transit. From the client:

bash
# Confirm the TCP port is reachable at all
nc -vz hostname 22

# Trace the path and watch for fragmentation / black holes (MTU issues)
sudo tracepath -m 100 hostname

# Try forcing a smaller MTU on the client interface as a test (replace eth0 / value)
# A successful connection after lowering MTU points to a path-MTU problem.
sudo ip link set dev eth0 mtu 1400

If nc cannot reach port 22, a firewall or network device is blocking or resetting the connection. If lowering the MTU lets the handshake complete, the path has an MTU/fragmentation issue that should be fixed on the network (enable Path MTU Discovery or correct the offending device). Revert any temporary MTU change once diagnosed.

8Wait out or whitelist temporary rate limiting

Many of the server-side causes (fail2ban bans, brute-force throttling) are temporary. If you cannot immediately access the server to unban your IP:

bash
# Wait for the ban window to expire, then retry
ssh user@hostname

# If you have out-of-band access, whitelist your IP in fail2ban so it is never banned
sudo fail2ban-client set sshd addignoreip <your-ip>
# Or persist it in /etc/fail2ban/jail.local under [DEFAULT]:
#   ignoreip = 127.0.0.1/8 <your-ip>

Whitelisting your own management IP avoids future lockouts without weakening protection against other sources.

Advanced notes

The kex_exchange_identification error occurs at the very start of the SSH protocol handshake, before any algorithm negotiation or authentication. This is what distinguishes it from Unable to negotiate ... no matching key exchange method (a true KEX algorithm mismatch, which happens *after* both sides exchange banners) and from authentication failures like Permission denied (publickey). If you only ever see this error before the server's version banner, the problem is connectivity or server-side gatekeeping, not crypto algorithms or credentials.

Server-side library updates: After glibc or OpenSSL upgrades, sshd may keep running against old, partially-unmapped libraries until it is restarted, which can cause it to close connections. Restart sshd after system library updates (sudo systemctl restart ssh sshd).

Brute-force defense interplay: Under a brute-force attack, both MaxStartups throttling and fail2ban bans can reject legitimate connections. Inspect logs for attack patterns, whitelist your management IP, and consider rate-limiting at the firewall (e.g. iptables/nftables connection-rate rules) rather than just raising MaxStartups.

MTU/black-hole connections: On VPNs or tunnels, ICMP being filtered breaks Path MTU Discovery, so large handshake packets are silently dropped. Lowering the client MTU or enabling MSS clamping on the gateway resolves these cases.

Frequently asked questions

What does "kex_exchange_identification: Connection closed by remote host" mean?
An SSH connection happens in phases. The very first phase is the protocol/version identification and key exchange (KEX) banner exchange, where the client and server announce themselves and begin negotiating encryption. The kex_exchange_identification: Connection closed by remote host error means the server (or something in front of it) dropped the TCP connection before it ever sent its identification string.
How do I fix "kex_exchange_identification: Connection closed by remote host"?
SSH fails during the key-exchange identification handshake because the server closes the TCP connection before negotiation finishes. It's a connectivity or server-side issue (fail2ban, MaxStartups, firewall), not authentication.
What causes "kex_exchange_identification: Connection closed by remote host"?
Your IP has been blocked by fail2ban, DenyHosts, or a similar intrusion-prevention tool on the server The SSH daemon has hit its MaxStartups limit and is refusing new unauthenticated connections A firewall on the client, server, or network path is resetting or dropping the connection
Is the "kex_exchange_identification: Connection closed by remote host" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading