Who tried to log in over SSH
Open any public server's SSH log and you'll find hundreds of strangers trying to log in. Most of it is harmless noise. Here's where the log lives, how to count the attempts, and which lines actually deserve your attention.
Published . Debian and Ubuntu with systemd and OpenSSH; notes cover Debian 13, where last, lastb and lastlog were removed.
- Why look
- The journal: journalctl -u ssh
- auth.log, if you have it
- Reading the lines
- Count the failed attempts
- last, lastb and lastlog
- What's normal, and when to act
Why look
The SSH log answers two questions: is anyone getting in who shouldn't, and is the noise bad enough to do something about. The first one matters most. A thousand failed attempts from bots is normal. One successful login you don't recognise is not.
The journal: journalctl -u ssh
On systemd systems, sshd's messages always go to the journal. The unit name depends on the distribution. Debian and Ubuntu call it ssh.service, with sshd.service only as an alias. Red Hat-family systems call it sshd.service. Use the real name, since journal entries are recorded under it:
# Debian and Ubuntu
sudo journalctl -u ssh --since today
# Red Hat Enterprise Linux and related systems
sudo journalctl -u sshd --since today
Add -f to follow new lines as they arrive, --since yesterday for a longer view, or -g to filter by a pattern. -g is case-insensitive when the pattern is all lowercase:
sudo journalctl -u ssh --since yesterday -g "accepted|failed|invalid user"
auth.log, if you have it
If rsyslog is installed, the same messages are also written to /var/log/auth.log on Debian and Ubuntu. Debian 12 and later don't install rsyslog by default, so on a fresh Debian server the file may not exist. That's expected; use the journal.
sudo grep -E "sshd.*(Accepted|Failed|Invalid user)" /var/log/auth.log | tail -n 50
Reading the lines
OpenSSH writes a small set of fixed messages. These are the ones to know:
Accepted publickey for deploy from 203.0.113.7 port 51234 ssh2: ED25519 SHA256:...
Failed password for root from 198.51.100.23 port 40112 ssh2
Failed password for invalid user admin from 198.51.100.23 port 40188 ssh2
Invalid user oracle from 198.51.100.41 port 55320
- Accepted: someone logged in. Check the user, the method and the source address. These are the lines that matter.
- Failed password for root: someone guessed a password for a real account.
- invalid user: the username doesn't exist on the server. This is almost always a bot working through a list.
- maximum authentication attempts exceeded: a client tried too many methods or keys in one connection and was disconnected.
Count the failed attempts
To see which addresses try hardest, pull the address out of each failure line and count them:
sudo journalctl -u ssh --since today --no-pager -g "failed password|invalid user" \
| grep -oE "from [0-9a-f.:]+" | sort | uniq -c | sort -rn | head -n 20
And the usernames they try:
sudo journalctl -u ssh --since today --no-pager -g "invalid user" \
| grep -oE "[Ii]nvalid user [^ ]+" | awk '{print $3}' | sort | uniq -c | sort -rn | head
Expect to see admin, test, oracle, ubuntu and other common names. List every successful login too, and read it line by line:
sudo journalctl -u ssh --since "2026-10-01" --no-pager -g "accepted"
last, lastb and lastlog
These older tools read binary login records instead of the log. On Ubuntu 24.04 and Debian 12, last and lastb come with util-linux, and lastlog with the login package:
last -i -n 20 # recent logins from /var/log/wtmp, with IP addresses
sudo lastb -i -n 20 # failed logins from /var/log/btmp
lastlog # the most recent login of each account
last shows sessions that actually started, including logins on the console. lastb reads failures from /var/log/btmp and needs root.
Debian 13 removed all three. The util-linux package no longer ships last or lastb, and the login package no longer ships lastlog, because the old file formats break in 2038. The replacements are wtmpdb (package wtmpdb) for last, and lastlog2 (packages lastlog2 and libpam-lastlog2) for lastlog. For failed logins, the release notes point to lslogins --failed. The journal works the same on all of them.
Thousands of failures are noise. One success you can't explain is an incident. If you find an Accepted line for a user, key or address you don't recognise, assume the account is compromised: lock it, check ~/.ssh/authorized_keys for keys you didn't add, and look at what that session did.
What's normal, and when to act
Any server with port 22 open to the internet gets constant scanning. Hundreds or thousands of failed attempts a day, mostly against root and made-up usernames, from addresses all over the world, is ordinary background noise. It doesn't mean you're being targeted.
What it should push you to do:
- Failed password lines for real users mean password login is still on. Turn it off: disable SSH password authentication.
- A lot of noise makes the log hard to read. Fail2ban cuts it down by banning repeat offenders.
- Accepted logins you can't place need investigating now, not later.
Checking once is easy. Checking every week is what catches problems, so make it a habit, or set up something that alerts you to new successful logins.
Stenvakt can collect this for you. Its Review is a read-only security and health check of every server. With Pro, Watch keeps monitoring and alerts you, and you can export the review, activity reports and a logins CSV. It's a Mac app and isn't out yet: get early access.
Sources
- Ubuntu manpages: journalctl(1)
- Ubuntu manpages: last(1) and lastb
- Debian 13 release notes: last, lastb and lastlog removed; wtmpdb and lastlog2
- OpenSSH source: auth.c (the log messages for accepted, failed and invalid-user logins)
- Debian openssh package: ssh.service (Alias=sshd.service)