Read Last Login Records Safely with lastlog

lastlog is the quickest way to see when every account on a box last logged in, handy on an unfamiliar server. It also shows whether an account has ever logged in at all. You will finish able to check one account, filter by age, and recognise a user who has never logged in. The examples use lastlog from the Ubuntu login package, version 1:4.13+dfsg1-4ubuntu3.2. Its manual identifies the underlying implementation as shadow-utils 4.13.

Allow about ten minutes. You need a shell and read access to /var/log/lastlog; ordinary inspection normally does not need sudo. This guide reads the database first. The commands that set or clear a record change login history and are treated separately.

1. Confirm the installed command

Check the local help before copying an option from a different distribution. This is a read-only command:

$ lastlog --help
Usage: lastlog [options]

Options:
  -b, --before DAYS             print only lastlog records older than DAYS
  -C, --clear                   clear lastlog record of an user (usable only with -u)
  -h, --help                    display this help message and exit
  -R, --root CHROOT_DIR         directory to chroot into
  -S, --set                     set lastlog record to current time (usable only with -u)
  -t, --time DAYS               print only lastlog records more recent than DAYS
  -u, --user LOGIN              print lastlog record of the specified LOGIN

Checkpoint: the installed help is the contract for this machine. This build in particular has no --version option, package identity is checked separately:

$ dpkg-query -W -f='${Package} ${Version}\n' login
login 1:4.13+dfsg1-4ubuntu3.2

2. Inspect one account

Start with your own login name so the output is easy to recognise:

$ lastlog -u "$(id -un)"
Username         Port     From                                       Latest
alice            pts/4    203.0.113.53                              Thu Sep 24 16:01:22 +0100 2026

Your username, terminal, source address and time will differ. The command reads the record for the named account and does not log you in again. Use an explicit account name when checking a service or shared account:

$ lastlog --user ACCOUNT_NAME

Replace ACCOUNT_NAME with an existing login name. Do not paste an untrusted value into a larger shell command without quoting it.

3. Read the complete report

With no options, lastlog prints current users in the order they appear in /etc/passwd. It reports the login name, port, source address and latest login time:

$ lastlog
Username         Port     From                                       Latest
root             pts/0    203.0.113.72                              Fri Jul 24 21:21:24 +0100 2026
daemon                                                              **Never logged in**
bin                                                                 **Never logged in**

Rows marked **Never logged in** are not failed lookups, they mean no last login record exists for that user. The output is based on current users, so records for accounts that have since been deleted may still exist in the database but are not shown by this command.

Large or busy systems can appear to pause while the report walks through gaps in user IDs. That is a documented consequence of sparse or widely spaced UIDs, not proof the process has frozen. Wait before interrupting it, or narrow the query with -u.

4. Filter by login age

Use -t DAYS for records more recent than the given number of days. This asks for logins within the last 30 days:

$ lastlog --time 30

Use -b DAYS for records older than the given number of days:

$ lastlog --before 365

These filters compare against the stored last login time. A never-logged-in entry has no successful login time to compare, so it is normally worth inspecting that account explicitly as well. The boundary is calculated at runtime, so output changes as the clock moves.

Checkpoint: combine a filter with one user when a full report would be distracting:

$ lastlog --time 30 --user ACCOUNT_NAME

5. Use a numeric user range carefully

The -u argument accepts a login name, numeric user ID or range. A range can be written as MIN-MAX, -MAX or MIN-:

$ lastlog --user 1000-1010

Use this once you have already chosen a bounded UID interval, do not assume UID ranges map neatly to human users on a directory-backed system. A bad name or malformed range returns an error instead of a report:

$ lastlog --user definitely-no-such-user
lastlog: Unknown user or range: definitely-no-such-user
$ printf 'exit status: %s\n' "$?"
exit status: 1

A non-zero status is useful in scripts. Treat it as a lookup or input failure, not evidence that nobody has logged in.

6. Keep the database intact

The data comes from /var/log/lastlog. It is a sparse database, so ls -l can show a large apparent size even though the allocated disk blocks are much smaller. That is normal:

$ ls -ls /var/log/lastlog
28 -rw-rw-r-- 1 root utmp 296380 Sep 24 16:01 /var/log/lastlog

Do not rotate, truncate, copy or process this file with tools that do not preserve sparse files, the manual specifically warns against rotating it. If you need an archive, choose a backup method that understands sparse files first, and test the restore procedure on a non-production copy.

Warning: lastlog -S --user ACCOUNT_NAME sets a user's record to the current time, while lastlog -C --user ACCOUNT_NAME clears it. Both require an explicit user and change audit data, and both normally require elevated privileges. Do not run either as a diagnostic shortcut. There is no general undo command in lastlog, restoring a previous value requires a trustworthy backup of the database and careful operational recovery.

The -R CHROOT_DIR option applies changes inside a chroot and accepts only an absolute path. Treat it as an administrative operation, not a way to inspect an arbitrary directory tree. Confirm the target and account database before using it.

Done means