Watch at EaseStories. Answers. Perspective.

Technology · PRACTICAL GUIDE

SSH says “kex_exchange_identification: Connection closed”? Correlate the pre-auth boundary first

This message is earlier than a normal login failure. Freeze the effective route, capture the client stop point, align edge and sshd logs, and change only the component that actually closed the socket.

Diagram of the client, network edge, SSH listener, identification exchange and later authentication.
Original Watch at Ease illustration: mark the last proven SSH boundary before touching keys or limits. Watch at Ease

The string kex_exchange_identification: Connection closed by remote host does not prove that a private key is wrong. It says the TCP path reached a peer and the connection ended around SSH identification or early key exchange, before a normal user-authentication diagnosis is justified.

Treat the incident as a three-vantage-point timeline: client, network entry point and SSH daemon. The same message can follow a wrong port, a proxy or firewall decision, an sshd startup limit, a source-address penalty or an explicit refusal rule.

Freeze the effective endpoint and one failure timestamp

Record the exact host, resolved address, port, source address, ProxyJump or ProxyCommand, VPN state and caller. Save one UTC timestamp and the complete ssh -vvv trace for a single attempt.

Do not assume a familiar hostname reached the expected sshd. A load balancer, NAT rule, hosting control-panel port, jump host or stale DNS answer can accept TCP and still close before SSH authentication.

Mark the last protocol boundary the client actually reached

Look for the server identification line and the first SSH key-exchange message in the client trace. If the peer never sends an SSH banner, investigate the listener and edge route before user keys.

RFC 4253 requires both sides to send an identification string after the connection is established. A closure here is a transport or pre-authentication observation, not evidence that authorized_keys rejected the user.

Correlate the edge decision and sshd pre-authentication log

At the same timestamp, read firewall, NAT, load balancer, proxy and host security logs, then the sshd journal. Confirm which backend accepted the socket and whether sshd logged a drop, refusal or configuration failure.

Read effective sshd values, including Match results for the client source, with a configuration test appropriate to the host. Prefer targeted temporary logging over an unbounded global debug level, and protect user data in logs.

Classify the close before changing a limit or key

Separate wrong destination or no SSH listener from MaxStartups pressure, PerSourceMaxStartups, PerSourcePenalties, RefuseConnection, LoginGraceTime expiry and an external policy tool. Evidence must choose the branch.

Do not increase MaxStartups just because a forum answer mentions it. The current default uses probabilistic early drop, and a higher ceiling can raise load without correcting a wrong route, abusive traffic or a source-specific policy.

Apply one minimal fix and verify forward progress

Correct the proved mismatch: route to the intended listener, repair the failing proxy/backend, fix a precise Match rule, exempt a trusted monitor where policy permits, or right-size a demonstrated pre-authentication capacity limit.

Make one controlled retry from a known source. Verify the client receives the intended SSH identification, sshd logs the same attempt, and the session reaches the expected authentication method. Then test one real command without disabling safeguards globally.

Checklist aligning client, edge and sshd evidence at one timestamp before a controlled retry.
Original Watch at Ease illustration: align client, edge and sshd evidence before one controlled retry. Watch at Ease