sshd Linux auth.log / journal Triage: low

sshd "pam_unix(sshd:auth): check pass; user unknown": What It Means

Published

pam_unix was asked to check a password for a name it has no account record for, so the attempt failed before any password was compared — and the line deliberately leaves out both the name and the source address.

What it looks like

Oct 18 03:51:11 web1 sshd-session[48211]: pam_unix(sshd:auth): check pass; user unknown

  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. 4PAM module — Module pam_unix, PAM service sshd, auth stage

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]: pam_unix(sshd:auth): check pass; user unknown
Oct 18 03:51:14 web1 sshd-session[48214]: pam_unix(sshd:auth): check pass; user unknown
Oct 18 03:51:19 web1 sshd-session[48221]: pam_unix(sshd:auth): check pass; user unknown

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

check pass; user unknown

48,083

lines · about 1,603 a day

Last seen 6 October 2026

None since the server went key-only on 6 October 2026 — turning off password authentication removed this line entirely.

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 Linux-PAM 1.7.0 — the versions this server runs. Each links to the exact line.

What it means

The prefix tells you who wrote the line: the pam_unix module, running under the PAM service sshd, in the auth stack. The message itself comes from pam_unix’s password-checking path.

That code first tries to obtain a usable password record for the name the client supplied. If it gets one, it hands the comparison to the external helper binary — the path that produces an ordinary authentication failure when the password is simply wrong. If it does not, it takes the branch the source marks “user’s record unavailable”: there is nothing to compare the password against, so the check fails immediately and this line is logged.

Two details of the logging are worth knowing:

  • The name is removed on purpose. By default pam_unix clears the name and logs the bare check pass; user unknown. With the module’s audit option it logs check pass; user (%s) unknown instead. The source explains why the default is the quiet one: “this might be a typo and the user has given a password instead of a username. Careful with this.”
  • Silence is also possible. The bare line is written when debug logging is on, or when the password structure came back NULL — the “no such account at all” case. If a record exists but no usable hash does, and debug is off, pam_unix logs nothing and moves on, because, in the words of the comment, “don’t log failure as another pam module can succeed”.

So in practice this line is your “the account does not exist here” signal from the PAM side, the counterpart to sshd’s own Invalid user line.

Is it an attack?

Almost always it is automated guessing, but the shape around it decides.

PatternReading
One or two lines around a user’s successful loginA typo, or a password pasted into the login prompt
One line per connection, many connections, each PID also carrying Invalid user <name> from <ip>Internet-wide SSH scanning working through a name list
Several lines on one PIDOne client retrying several passwords for a name you do not have (MaxAuthTries, default 6, caps the attempts per connection)
Lines interleaved with Failed password and pam_unix(sshd:auth): authentication failure for names you do haveThe same source is also hitting real accounts — raise priority
Any Accepted line from a source that produced theseStop triaging and investigate the session

The useful property of this message is that it separates misses from near-misses. Guesses like ftpuser, solana, test or user1 land here because no such account exists; guesses at names that exist on the host — root always, ubuntu or postgres where an image or package created them — never reach this branch, because a record was found and the password was actually checked.

How to investigate

The line carries no address, so every pivot goes through the PID.

# Debian/Ubuntu: unit is ssh. RHEL/Fedora: journalctl -u sshd, log /var/log/secure
sudo journalctl -u ssh --since "24 hours ago" | grep 'check pass; user unknown'

# How many, per day, in the file log
sudo grep -c 'pam_unix(sshd:auth): check pass; user unknown' /var/log/auth.log

# The whole story of the connections that produced them: PID -> all its lines
for pid in $(sudo grep -oP 'sshd-session\[\K[0-9]+(?=\]: pam_unix\(sshd:auth\): check pass; user unknown)' \
             /var/log/auth.log | sort -u | tail -20); do
  echo "--- pid $pid"; sudo grep "sshd-session\[$pid\]" /var/log/auth.log
done

# Names and sources, taken from sshd's own lines rather than from PAM
sudo grep -oP 'Invalid user \K\S+ from \S+' /var/log/auth.log | sort | uniq -c | sort -rn | head -20

# The only question that changes severity
sudo grep -E 'Accepted (publickey|password)' /var/log/auth.log | tail -50

If the attempted names turn out to be real accounts, you are reading the wrong message — those attempts log an authentication failure instead. For an exported auth.log, the browser log analyzer groups the surrounding sshd lines by source, and the SSH brute-force rule encodes the one-source-many-names pattern as a detection.

How to stop it

The line is only ever written when the PAM auth stack runs, so the fix is to stop running it for strangers.

  • Turn off password-based logins. PasswordAuthentication no (the default is yes) and, with PAM enabled, KbdInteractiveAuthentication no (also yes by default) — the manual notes PAM keyboard-interactive authentication usually serves an equivalent role to password authentication, and recommends disabling one of the two. With neither enabled there is no password for pam_unix to check, and these lines stop.
  • Keep port 22 off the open internet where you can: firewall it to known ranges, or front it with a VPN or bastion. Nothing reduces the volume more.
  • 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.
  • Tighten the per-connection limits: MaxAuthTries (default 6) and LoginGraceTime (default 120 seconds).
  • Restrict who may log in at all 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 already disables password and keyboard-interactive authentication for root.
sudo sshd -t && sudo systemctl reload ssh

Validate the configuration before reloading, and keep a working session open until a new one succeeds.

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".
  • authentication failure; logname=… uid=… euid=… tty=… ruser=… rhost=… PAM's pam_unix module rejected the credentials sshd asked it to check — the line names the client address in rhost= and, when it has one, the account in user=.
  • 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.
  • password check failed for user (…) PAM's password helper checked the password offered for the named account and it did not pass — a wrong password, or a name it could not resolve — and the line itself carries no address, so the sshd lines beside it are what tell you where it came from.

Detect it

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

Frequently Asked Questions

Why does the line not contain a username or an IP address?
Because pam_unix sets the name to NULL before logging this variant. The source carries a comment explaining the caution — "this might be a typo and the user has given a password instead of a username. Careful with this." — so writing the string to syslog risks writing somebody's password there. The module's audit option logs "check pass; user (%s) unknown" with the name instead. For the address and the account, read sshd's own lines on the same PID.
How is this different from sshd's "Invalid user" line?
They come from different programs about the same attempt. sshd writes "Invalid user <name> from <ip> port <n>" when it decides the requested account is not usable, and names both the account and the source. This line is written later in the same connection by pam_unix, when the PAM auth stack actually tries to verify a password and finds no record to verify it against. Seeing both for one PID is normal.
Does this line mean a password was actually submitted?
It means the PAM authentication stack was run for that connection, which sshd_config ties to password and keyboard-interactive authentication — UsePAM "will enable PAM authentication using KbdInteractiveAuthentication and PasswordAuthentication in addition to PAM account and session module processing for all authentication types". Whatever the client sent was never compared against anything, because there was no stored hash for that name.
Can I make the line show which account was tried?
Yes, pam_unix has an audit option that logs the name in parentheses, but weigh it against the comment in the module source about users typing a password into the login prompt — that string then lands in auth.log and in your SIEM. Correlating by PID with sshd's "Invalid user" lines gives you the same name without that risk.

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.