Connection closed by UNKNOWN port 65535 is a SERVER-SIDE sshd log line, not a client error. It almost always means harmless internet scanner noise or a TCP load balancer health check hitting port 22 and dropping before the banner.
This line appears in the SSH server's logs (`/var/log/auth.log`, `/var/log/secure`, or `journalctl -u ssh`), not on your client. sshd writes it when a remote peer opens a TCP connection to port 22 and then closes it before completing the protocol banner/key exchange (`kex_exchange_identification`). Because the connection never got far enough to identify the peer, sshd substitutes placeholder values: `UNKNOWN` means the reverse-DNS lookup of the peer's IP failed (or wasn't attempted), and `port 65535` is a garbage/placeholder source port shown when the real port could not be recorded. The overwhelmingly common cause is internet background noise. Any host with port 22 exposed to the internet is continuously probed by automated scanners and botnets that connect, fingerprint, and immediately disconnect. These show up as a steady stream of `Connection closed by UNKNOWN port 65535` from many different IPs. This is normal and, by itself, harmless — it is not evidence of a breach. The second common cause is infrastructure health checks. In cloud environments a TCP load balancer (AWS NLB/ELB, GCP, Azure LB), a Kubernetes service probe, or a monitoring tool repeatedly opens a TCP connection to port 22 to check liveness, then closes it without speaking SSH. These produce the same log line at regular intervals from a small set of internal/LB IPs. This error is NOT a diagnostic of your own outbound SSH session failing — if your client can't connect, debug that separately on the client side.
First, locate where you are seeing the message. This string is written by sshd on the machine being connected TO, not by the ssh client. Check the server logs:
# Debian/Ubuntu
sudo journalctl -u ssh --since "1 hour ago" | grep "Connection closed"
sudo grep "Connection closed" /var/log/auth.log
# RHEL/Fedora/Amazon Linux
sudo journalctl -u sshd --since "1 hour ago" | grep "Connection closed"
sudo grep "Connection closed" /var/log/secureIf the message is in these logs and NOT printed by an ssh command you ran, then this is inbound traffic to your server. That is the normal case and the rest of these steps apply. If instead your own ssh client prints a 'Connection closed' error, skip to the last step.
Determine whether this is many random IPs (scanner noise) or a few repeating IPs (health check / proxy). Extract and count the source addresses:
# Pull the offending lines and count by source IP (systemd)
sudo journalctl -u ssh --since "24 hours ago" \
| grep "Connection closed by" \
| grep -oE 'by [0-9.]+ port' \
| awk '{print $2}' | sort | uniq -c | sort -rn | head
# From a logfile instead
sudo grep "Connection closed by" /var/log/auth.log \
| grep -oE 'by [0-9.]+ port' | awk '{print $2}' \
| sort | uniq -c | sort -rn | headInterpretation:
- Many distinct IPs, low count each = internet background scanning. Harmless. Proceed to hardening.
- One or a few IPs, high regular frequency = likely a load balancer, health check, monitor, or proxy. Identify the owner before changing anything.
If the noise comes from a small set of IPs, confirm whether it is your own infrastructure probing port 22.
# Is the suspect IP inside your VPC/private range or a known LB subnet?
ip route get <suspect-ip>
whois <suspect-ip> 2>/dev/null | grep -iE 'orgname|netname|descr'Common legitimate sources:
- AWS NLB/ELB / GCP / Azure LB: TCP health checks open the target port, then close it. Check your target group / backend health-check config — if it targets port 22 with a TCP probe, this log is expected. Consider pointing the health check at a dedicated port or an HTTP endpoint instead of 22.
- Kubernetes: a tcpSocket liveness/readiness probe on the SSH port produces this every probe interval.
- Monitoring/uptime tools doing bare TCP connects.
If you confirm it is your own health check, the log is benign — you can either accept it or move the probe off port 22 to silence it.
If the source is many random internet IPs, this is ambient scanning and is expected for any internet-facing port 22. It is not an intrusion. You can reduce log volume and exposure without disabling any security:
# See how much of your auth log is just closed connections
sudo journalctl -u ssh --since "24 hours ago" \
| grep -c "Connection closed by"Genuine ways to cut the noise:
- Restrict access at the network layer so scanners never reach port 22 (cloud security group / firewall allowing SSH only from known IP ranges or a VPN).
- Move SSH off port 22 to a high port — this does not add real security but dramatically reduces drive-by scanner noise.
- Leave verbose logging alone unless it is overwhelming; the lines themselves are informational.
Since the port is being probed continuously, make sure it is properly hardened. These are safe, recommended settings in /etc/ssh/sshd_config:
sudo nano /etc/ssh/sshd_config# Disable password auth; use keys only
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
# Disallow root login over SSH
PermitRootLogin no
# Restrict who may log in
AllowUsers deploy adminValidate the config before reloading so you don't lock yourself out:
sudo sshd -t # syntax check; fix any reported errors
sudo systemctl reload ssh # or: sudo systemctl reload sshdKeep a second session open while testing so you can revert if a key/login problem surfaces. Note: leave StrictHostKeyChecking at its default — never set it to no, and do not set MaxAuthTries 0 (that rejects all authentication, it does not make it unlimited).
fail2ban watches the SSH log and temporarily blocks IPs that repeatedly fail or abuse the port, which trims both the noise and brute-force attempts:
# Debian/Ubuntu
sudo apt-get install -y fail2ban
# RHEL/Fedora (EPEL)
sudo dnf install -y fail2ban
sudo systemctl enable --now fail2banMinimal jail config in /etc/fail2ban/jail.local:
[sshd]
enabled = true
port = ssh
maxretry = 5
bantime = 1h
findtime = 10msudo systemctl restart fail2ban
sudo fail2ban-client status sshd # see banned IPsBare 'Connection closed' probes that never attempt auth may not always trip the default filter, but fail2ban still handles the brute-force traffic that usually accompanies them.
If you determined in step 1 that an actual user/system you care about cannot connect (and their attempt is the source of the closed connection), debug that connection separately — this is a different problem from ambient noise. On the CLIENT machine:
ssh -vvv user@hostLook for where it stalls around kex_exchange_identification. Common real causes:
- Firewall / network path dropping the connection mid-handshake.
- MTU / MSS issues on VPNs or tunnels — try lowering MTU or enabling MSS clamping on the path.
- A corporate proxy blocking raw SSH. If the target is GitHub, SSH over HTTPS works around many proxies:
ssh -T -p 443 [email protected]Correlate the client's source IP with the server log entry to confirm you are debugging the same connection rather than unrelated scanner noise.
Why 'UNKNOWN' and 'port 65535': sshd logs the peer by reverse-DNS name when available; UNKNOWN means the PTR lookup failed or UseDNS resolution did not complete before the socket closed. Port 65535 (2^16 - 1) is a placeholder substituted when the real ephemeral source port could not be recorded because the connection was torn down before sshd captured it. Neither value indicates a specific attacker capability — they are artifacts of an early TCP close.
Protocol context: the SSH exchange begins with a plaintext banner/version exchange, then key exchange (kex). 'Connection closed by ... port 65535' is logged when the peer disconnects during or before that initial exchange. A bare TCP connect-and-close (scanner, nc -z, LB TCP probe) produces exactly this because the peer never sends an SSH banner.
Useful inventory commands (informational, for the server's own capabilities):
ssh -Q kex # supported key exchange algorithms
ssh -Q cipher # supported ciphers
ssh -Q key # supported host key types
sudo sshd -T | grep -iE '^(kexalgorithms|ciphers|macs|hostkey|permitrootlogin|passwordauthentication)'These help you audit what your sshd actually offers. Note that algorithm mismatches (e.g. an old client vs. a modern server) usually surface as an explicit 'no matching key exchange method found' error on the client, NOT as this server-side closed-connection log — so do not chase KexAlgorithms based on this message alone. Likewise, never re-enable the deprecated ssh-rsa host key algorithm as a fix for this; it is unrelated and weakens security.
Distinguishing the cases at a glance: many unique IPs over time = internet noise; a tight set of IPs at a fixed cadence = health check/probe; a single IP matching a user you expected = investigate as a real client-side connectivity problem.
sign_and_send_pubkey: no mutual signature supported
How to fix "sign_and_send_pubkey: no mutual signature supported" in SSH
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
How to fix SSH man-in-the-middle attack warning in SSH
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: UNPROTECTED PRIVATE KEY FILE! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
How to fix "WARNING: UNPROTECTED PRIVATE KEY FILE!" in SSH
sign_and_send_pubkey: signing failed for RSA from agent: agent refused operation
How to fix "sign_and_send_pubkey: signing failed for RSA from agent: agent refused operation" in SSH
Bad owner or permissions on /home/user/.ssh/known_hosts
How to fix "Bad owner or permissions on known_hosts" in SSH