sshd Linux auth.log / journal Triage: medium

sshd "maximum authentication attempts exceeded": MaxAuthTries Reached

Published

One SSH connection used up every authentication attempt sshd allows it — the MaxAuthTries limit, 6 by default — so sshd logged the account name, source address and port and tore the connection down.

What it looks like

Oct 18 03:51:11 web1 sshd-session[48211]: error: maximum authentication attempts exceeded for invalid user admin from 203.0.113.7 port 54321 ssh2 [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. 4Level — Logged at error level
  5. 5User — The account name
  6. 6Source address — The client’s IP address
  7. 7Source port — The client’s source port; with the address it identifies one connection
  8. 8Protocol — SSH protocol version 2
  9. 9[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]: error: maximum authentication attempts exceeded for invalid user admin from 203.0.113.7 port 54321 ssh2 [preauth]
Oct 18 03:51:11 web1 sshd-session[48211]: Disconnecting invalid user admin 203.0.113.7 port 54321: Too many authentication failures [preauth]
Oct 18 04:02:37 web1 sshd-session[48502]: error: maximum authentication attempts exceeded for deploy from 198.51.100.22 port 40118 ssh2 [preauth]
Oct 18 04:02:37 web1 sshd-session[48502]: Disconnecting authenticating user deploy 198.51.100.22 port 40118: Too many authentication failures [preauth]

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

maximum authentication attempts exceeded for … from … port … ssh2

291

lines · about 9.7 a day · 19 source addresses

Last seen 24 October 2026

Disconnecting …: …

291

lines · about 9.7 a day · 19 source addresses

Last seen 24 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.

maximum authentication attempts exceeded for … from … port … ssh2

  • maximum authentication attempts exceeded for %s%.100s from %.200s port %d ssh2 message · auth.c:335 (OpenSSH)

Disconnecting …: …

  • Too many authentication failures disconnect reason · auth.c:341 (OpenSSH)
  • Disconnecting %s: %.100s message · packet.c:2104 (OpenSSH)
  • %.200s%s%s port %d connection id: preamble, address, port · packet.c:2004 (OpenSSH)
  • authctxt->valid ? "authenticating " : "invalid ", user); preamble: authenticating or invalid user · auth2.c:312 (OpenSSH)
  • %suser %s preamble format · auth2.c:311 (OpenSSH)
  • mon_dispatch == mon_dispatch_postauth20 ? "postauth" : "preauth"); the [preauth] tag on lines from the pre-authentication process · monitor.c:481 (OpenSSH)

What it means

sshd counts failed authentication attempts for each connection separately. In the authentication loop, a failed attempt increments that connection’s failure counter — the code makes one exception, allowing the client’s opening none probe “without failure penalty” on the first attempt. When the counter reaches the configured limit, sshd calls auth_maxtries_exceeded(), which produces both of these lines back to back:

  1. error: maximum authentication attempts exceeded for %s%.100s from %.200s port %d ssh2 — the account, the client address and the client source port.
  2. The disconnect itself: the function immediately tears the connection down with the reason Too many authentication failures, and the packet layer logs that as Disconnecting %s: %.100s, where the first %s is the connection identifier %.200s%s%s port %d — logging preamble, address, port.

The limit is MaxAuthTries, which sshd_config(5) describes as “the maximum number of authentication attempts permitted per connection”, adding that “once the number of failures reaches half this value, additional failures are logged” and that “the default is 6”. That second half is why you normally see a few Failed password lines on the same PID before this pair.

Three details decide how you read the pair:

  • The account name. On the error line the name is prefixed with invalid user when sshd could not look up a usable account record, and printed bare when it could. The disconnect line encodes the same distinction in its preamble — invalid user admin versus authenticating user deploy — because sshd sets that preamble when it handles the first authentication request on the connection.
  • The address and source port. The port identifies the single TCP connection, which is how you tie these two lines to the Failed password or key-offer lines that preceded them under the same PID.
  • The [preauth] tag. sshd’s monitor appends it to messages relayed from the pre-authentication process, so a tagged pair is proof the connection ended before any session existed.

Is it an attack?

Usually yes on an internet-facing host, but the shape matters.

PatternReading
invalid user plus a different guessed name on every connection from one sourceName guessing and brute force — same story as Invalid user lines
One real account, many connections from one source, each ending in this pairTargeted brute force against an account that exists
One source, a handful of real accounts, a few attempts eachSpraying spread across connections to stay under lockout-style controls
A known workstation, a real account, no password failures before itA client offering more public keys than the limit allows
Any source that later appears on an Accepted lineStop triaging and investigate the session

The pair never tells you a password was correct; for that you need the Failed password and PAM lines on the same PID, or the PAM: more authentication failures summary.

How to investigate

Pivot on the source address, then on the PID.

# Last 24 hours (Debian/Ubuntu unit is ssh; on RHEL/Fedora use -u sshd)
sudo journalctl -u ssh --since "24 hours ago" \
  | grep -E "maximum authentication attempts exceeded|Too many authentication failures"

# Busiest sources (/var/log/auth.log; on RHEL/Fedora /var/log/secure)
sudo grep -oP 'maximum authentication attempts exceeded for (?:invalid user )?\S+ from \K\S+' \
  /var/log/auth.log | sort | uniq -c | sort -rn | head -20

# Which account names clients burned their attempts on
sudo grep -oP 'maximum authentication attempts exceeded for \K(?:invalid user )?\S+' \
  /var/log/auth.log | sort | uniq -c | sort -rn | head -20

# The whole connection, by PID
sudo grep 'sshd-session\[48502\]' /var/log/auth.log

# Did any of those sources actually get in?
sudo grep -E "Accepted (password|publickey)" /var/log/auth.log | tail -50

Check every bare (non-invalid) name against /etc/passwd: a real service or staff account being worked on is a different conversation from a thousand throwaway names. For an exported auth.log, the browser log analyzer groups the lines by source, and the SSH brute-force rule encodes the one-source-many-names pattern as a detection.

How to stop it

  • Take passwords out of the equation. PasswordAuthentication no (it defaults to yes) and, where PAM is enabled, KbdInteractiveAuthentication no — the manual notes PAM keyboard-interactive authentication usually serves an equivalent role to password authentication. After that, guessed passwords cannot consume attempts at all.
  • Leave PerSourcePenalties enabled. Penalties are on by default; a client that disconnects after one or more unsuccessful authentication attempts is refused for 5 seconds by default, accumulating to a maximum of 10 minutes, with a 15-second minimum before enforcement begins.
  • Restrict 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, which disables password and keyboard-interactive authentication for root.
  • Keep LoginGraceTime tight (default 120 seconds) so slow guessing connections are cut sooner.
  • Tune MaxAuthTries with care. Lowering it shortens each connection but not the campaign, and setting it below the number of keys a legitimate agent offers will lock out your own users; those users can limit the keys offered with ssh -o IdentitiesOnly=yes -i <key>.
  • Do not expose port 22 to the whole internet. A firewall rule, VPN or bastion removes most of these lines outright.
sudo sshd -t && sudo systemctl reload ssh

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

Lines you will see next to it

  • … 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".
  • 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.
  • … more authentication failure…; logname=… uid=… euid=… tty=… ruser=… rhost=… pam_unix's end-of-connection tally of repeated password failures — the number printed is one less than the failures it counted, and the companion line fires when that count passes the module's compiled-in limit of 3.
  • 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.
  • …: 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: T1110.001T1110.003T1021.004

Frequently Asked Questions

Does this line mean the attacker got in?
No. sshd writes it at the moment it gives up on the connection, and the next thing the same code does is disconnect the client, so nothing was authenticated on that connection. What matters is whether the same source address appears later on an "Accepted publickey" or "Accepted password" line — that, not this message, is the sign of a successful login.
Why does one line say "invalid user deploy" and another just "deploy"?
The prefix is chosen from whether sshd found a usable account record for the name. If the lookup failed, the message is prefixed with "invalid user "; if it succeeded, only the bare name is printed on the error line and the disconnect line's preamble reads "authenticating user". A real account name means an attacker is working on something that actually exists on the host.
Can a legitimate client trigger this without guessing passwords?
Yes. Every refused authentication attempt counts toward the limit, including each public key a client offers from its agent, so a user whose agent holds more keys than MaxAuthTries allows can be disconnected before the right key is tried. Those cases come from a known address, name a real account and stop as soon as the client offers fewer keys.
Should I lower MaxAuthTries to stop brute force?
It helps a little but does not solve anything, because the manual defines the limit as per connection — a scanner simply opens another connection and keeps going. Turning off password and keyboard-interactive authentication, restricting who may log in, and keeping port 22 off the open internet change the outcome; the counter only changes how many tries fit in one TCP session.

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.