sshd Linux auth.log / journal Triage: low

sshd "Received disconnect from … port …": What the Reason Code Means

Published

The client told the server it was closing the connection — sshd logged the client's address and port, the numeric disconnect reason the client sent and the text that came with it.

What it looks like

Oct 18 03:51:11 web1 sshd-session[48211]: Received disconnect from 203.0.113.7 port 54321:11: Bye Bye [preauth]

  1. 1Time — When it was logged; this format has no year or time zone
  2. 2Host — The server’s host name
  3. 3Program — sshd-session, one process per connection, and its process ID: a connection’s lines share it
  4. 4Source address — The client’s IP address
  5. 5Source port — The client’s source port; with the address it identifies one connection
  6. 6Disconnect reason — Reason code 11 (SSH_DISCONNECT_BY_APPLICATION) from RFC 4253, then the text the client sent
  7. 7[preauth] — Logged before the user authenticated

Example lines as /var/log/auth.log shows them (/var/log/secure on RHEL and Fedora):

Oct 18 03:51:11 web1 sshd-session[48211]: Received disconnect from 203.0.113.7 port 54321:11: Bye Bye [preauth]
Oct 18 03:51:12 web1 sshd-session[48213]: Received disconnect from 198.51.100.22 port 40118:11: Bye Bye [preauth]
Oct 18 09:14:40 web1 sshd-session[51002]: Received disconnect from 192.0.2.44 port 51902:11: disconnected by user

On our own server, the 30 days to 25 October 2026

Received disconnect from … port …:…: …

26,084

lines · about 869 a day · 1,254 source addresses

Last seen 25 October 2026

LogTriage's production API server (Hetzner, Germany): port 22 open to the internet, key-only since 6 October 2026 (password and keyboard-interactive authentication off); nginx in front of the API on ports 80 and 443. Counted weekly from the sshd journal; no address ever leaves the server. More in the monthly attack report; which free blocklists already list these attackers is measured in the IP blocklist report, and you can check the addresses in your own log.

Where the line comes from

Format strings as written in the source of OpenSSH 10.2p1 — the versions this server runs. Each links to the exact line.

  • Received disconnect from %s port %d:%u: %.400s message · packet.c:1846 (OpenSSH)

What it means

An SSH client can end a connection politely by sending a disconnect packet that carries a numeric reason code and a human-readable string. sshd’s packet layer handles those packets unconditionally — the comment in the code is “Always process disconnect messages” — reads the 32-bit reason and the message out of the packet, writes this line, and returns SSH_ERR_DISCONNECTED, which ends the connection.

The format string is Received disconnect from %s port %d:%u: %.400s, so each line gives you four facts:

  • The client address, taken from the connection’s remote IP.
  • The client’s source port for that one TCP connection. Together with the PID in the syslog tag, this is how you tie the line to everything else that happened on the same connection.
  • The reason code, printed immediately after the port with no space — port 54321:11:. It comes straight out of the packet; 11 is SSH2_DISCONNECT_BY_APPLICATION, the code a client sends when the application itself decided to close.
  • The client’s message, truncated to 400 characters. It is written by the remote end, so treat it as attacker-controlled text, not as a statement of fact.

Two details are worth knowing. First, sshd logs this at INFO level only when it is the server side and the reason is SSH2_DISCONNECT_BY_APPLICATION — the code calls those “normal client exit notifications”. Any other reason code is logged at ERROR level. Second, unlike the Connection closed by … lines, this message contains no user preamble: the format uses the remote address directly, so the account the client was trying never appears here. The text after the code is whatever the client chose to send. Bye Bye is not OpenSSH’s — its client sends disconnected by user when a session ends — so a stream of Bye Bye lines points at a scripted client built on another SSH library.

Lines relayed from sshd’s pre-authentication child are tagged [preauth]; a line without that tag was written by the session process, typically when an authenticated session ends.

Is it an attack?

By itself, no — it is a client saying goodbye. What matters is what the same connection did first.

PatternReading
:11: with [preauth], one per connection, many connections from one source in minutesScripted client opening a connection per attempt — check the preceding lines
[preauth], preceded by Failed password or Invalid user on the same PIDBrute force or name guessing ending each attempt cleanly
[preauth], with no authentication lines at all on that PIDA survey — the client negotiated, looked at the host key or banner, and left
Many different account names in the preceding lines from one sourceUsername enumeration
No [preauth] tag, after an Accepted line for the same PIDA normal session ending
A reason code other than 11, or odd message textA non-OpenSSH client or library; the string is whatever its author chose
Any Accepted publickey/Accepted password from a source producing theseStop triaging and investigate the session

Because the reason and the text are supplied by the remote end, do not build detections on the message string alone — build them on the source address and the authentication outcome, as the SSH brute-force rule does.

How to investigate

Pivot on the source address first, then on the PID of a single connection.

# Last 24 hours from the journal (Debian/Ubuntu unit is ssh; RHEL/Fedora use -u sshd)
sudo journalctl -u ssh --since "24 hours ago" | grep 'Received disconnect from'

# Busiest sources (/var/log/auth.log; on RHEL/Fedora /var/log/secure)
sudo grep -oP 'Received disconnect from \K\S+' /var/log/auth.log \
  | sort | uniq -c | sort -rn | head -20

# Which reason codes and client messages you are actually seeing
sudo grep -oP 'Received disconnect from \S+ port \d+:\K\d+: [^[]*' /var/log/auth.log \
  | sort | uniq -c | sort -rn | head -20

# The full story of one connection, by PID
sudo grep 'sshd-session\[48211\]' /var/log/auth.log

# Lines with no [preauth] tag: sessions that had already authenticated
sudo grep 'Received disconnect from' /var/log/auth.log | grep -v '\[preauth\]'

# Did anything from these sources get in?
sudo grep -E 'Accepted (publickey|password)' /var/log/auth.log | tail -50

Compare the addresses from the first count with the ones in Failed password and Invalid user lines; a source that only ever disconnects is a scanner, a source that guesses accounts first is not. For an exported auth.log, the browser log analyzer groups these lines by source.

How to stop it

You cannot stop a remote client from sending a disconnect packet, so reduce the number of connections that reach sshd and the value of each one.

  • Do not expose port 22 to the whole internet. A firewall allow-list, a VPN or a bastion removes most of this volume outright.
  • Leave PerSourcePenalties enabled. The manual says penalties are on by default: a client that disconnects after one or more unsuccessful authentication attempts is refused for 5 seconds (authfail), one that disconnects without attempting authentication for 1 second (noauth), accumulating up to a maximum of 10 minutes, with a 15-second minimum before enforcement begins. The manual warns that noauth should be used cautiously, as it may penalise legitimate scanning tools such as ssh-keyscan(1).
  • Keep LoginGraceTime (default 120 seconds) and MaxAuthTries (default 6) tight, so a connection that lingers or guesses is cut off sooner.
  • Turn passwords off with PasswordAuthentication no (the default is yes) and, where PAM is enabled, KbdInteractiveAuthentication no — the manual notes PAM keyboard-interactive authentication usually serves an equivalent role to password authentication.
  • Limit who may log in with AllowUsers; by default login is allowed for all users, and patterns may take the USER@HOST form with CIDR host criteria. PermitRootLogin defaults to prohibit-password.
  • Leave LogLevel at its default of INFO. Lowering it to hide this message also hides the authentication lines you need; DEBUG levels are explicitly not recommended.
sudo sshd -t && sudo systemctl reload ssh

Validate the configuration before reloading, and keep an existing session open until a new one works.

Lines you will see next to it

  • Invalid user … from … port … sshd rejected the login because the name the client asked for is not a valid account on this host, so no password or key was ever checked against a real user.
  • … for … from … port … ssh2… sshd rejected a password authentication attempt — the line names the account that was tried, the client address and the client's source port, and marks names that are not usable accounts on this host with "invalid user".
  • Disconnected from … The client told sshd which account it wanted and then ended the connection before authentication succeeded, so the line names that account along with the source address and port.
  • Connection closed by … The client at the other end of the SSH connection went away — closed it cleanly, or reset it — and sshd logged the address, port and (if the client had already named an account) the user it was trying before it quit.
  • …: activating … penalty of … seconds for … sshd has accumulated enough penalty against one client address range to start refusing its connections, and the line names the address, the number of seconds left on the block and what the client did to earn it.

Detect it

MITRE ATT&CK: T1595.001T1110.001T1021.004

Frequently Asked Questions

What is the number between the port and the message?
It is the disconnect reason code the client put in its SSH_MSG_DISCONNECT packet, logged by sshd as an unsigned integer. Value 11 is SSH2_DISCONNECT_BY_APPLICATION — the application chose to close the session — which is why most lines read "port 54321:11:". The text after it is whatever string the client sent with that code.
How is this different from "Connection closed by"?
"Received disconnect" means the client sent a protocol disconnect packet announcing it was leaving, so sshd can print the reason code and the client's own message. "Connection closed by" and "Connection reset by" mean the peer simply went away and the packet layer or a system call reported it, with no reason to print.
Does the line tell me whether authentication succeeded?
No. It only records that the client ended the connection. Read the lines sharing the same PID and source port — Accepted, Failed password, Invalid user — to find out what happened before the disconnect. A "[preauth]" tag means the connection ended before authentication completed.
Should I alert on these lines?
Not on the line itself; on an internet-facing host it is one of the highest-volume sshd messages, because every bot that tries a few credentials and leaves produces one. Alert on the surrounding shape instead — one source naming many accounts, repeated password failures, or any Accepted line from a source that had been producing these.

Run your own auth.log through it

Paste or drop /var/log/auth.log (or journalctl -u ssh output) into the free browser analyzer: brute force, password spraying, a successful login after failures and invalid-user sweeps are flagged with the evidence lines. Nothing is uploaded.