Inspect Linux Sessions and Manage User Lifetimes with loginctl

loginctl can tell you who is logged in right now, but confuse its human-readable status with its script-friendly show output and automation breaks. This guide gets you inspecting sessions safely, telling the two output styles apart, and enabling or disabling a user's systemd manager after logout.

The examples use loginctl from systemd 255.4-1ubuntu8.17, provided by the installed systemd package. Allow about fifteen minutes. You need a shell on a system using systemd-logind. The inspection commands are normally unprivileged. Commands that change lingering or terminate sessions can require authentication and can disrupt work, so read each warning before running one.

1. Confirm the installed command

Check the binary and package before relying on option details. This is read-only:

$ command -v loginctl
/usr/bin/loginctl
$ loginctl --version
systemd 255 (255.4-1ubuntu8.17)
$ dpkg-query -W -f='${Package} ${Version}\n' systemd
systemd 255.4-1ubuntu8.17

Your package revision may differ. The useful version boundary here is the systemd major version, because loginctl commands and options have been added across releases. Check the installed manual when working on another host instead of copying assumptions from this guide.

2. List sessions, users and seats

Start with the three inventories. Add --no-pager so an unattended shell does not open less; add --no-legend when you want rows without column headings and footer text:

$ loginctl --no-pager list-sessions
SESSION  UID USER  SEAT  TTY
1        1000 alice  -     -
29116    1000 alice  -     pts/4

$ loginctl --no-pager --no-legend list-users
1000 alice

$ loginctl --no-pager --no-legend list-seats
seat0

Checkpoint: Write down the session ID or username you intend to inspect. If the list is empty, stop and investigate the host's logind setup rather than guessing an identifier.

3. Read a human-friendly status report

Use session-status when a person needs a quick report. With no ID it targets the caller's session, but that default only works when the calling process belongs to a known login session. In a script, CI job or container it may fail:

$ loginctl --no-pager session-status SESSION_ID
SESSION_ID - alice (1000)
           Since: ...
           State: active
            Unit: session-SESSION_ID.scope
                  ...

Replace SESSION_ID with a real value. The report includes runtime status and recent journal lines. Its layout is for reading, not parsing, and the journal line count defaults to 10. Use --lines=25 for a longer human report; --lines=0 is not a valid substitute for a machine-readable query because the option requires a positive integer.

For a user-level report, use the same pattern:

$ loginctl --no-pager user-status alice
alice (1000)
           State: active
        Sessions: SESSION_ID
            Unit: user-1000.slice
                  ...

Exact fields and journal text vary with the host. A successful exit status means loginctl completed the request, not that the user has a particular desktop, terminal or activity state.

4. Query stable properties for scripts

Use show-session, show-user and show-seat when another program needs named properties. These commands emit Property=Value lines and suppress empty properties by default:

$ loginctl --no-pager --property=Id,User,Name,State,Type,Remote,Seat show-session SESSION_ID
Id=SESSION_ID
User=1000
Name=alice
State=active
Type=tty
Remote=no
Seat=

$ loginctl --no-pager --property=Name,User,State,Sessions show-user alice
Name=alice
User=1000
State=active
Sessions=SESSION_ID

Do not parse the pretty tree from session-status when you need a value. Select only the properties you need with repeated --property= options. Add --value when you need values without names, for example:

$ loginctl --no-pager --value --property=State show-user alice
active

The empty Seat= above is not an error: it means this session has no seat value. If you need to see unset properties while diagnosing a mismatch, add --all. For a session owned by the current loginctl process, show-session self is explicit, while show-session auto can fall back to the current user's graphical session. Neither default is a good replacement for an ID in a repeatable audit.

5. Enable lingering for a service account

User lingering makes a user manager start at boot and remain after logout, allowing that user to run long-lived user services without an active login. It changes persistent system state and may require authentication. Confirm the account first:

$ id backupsvc
uid=1005(backupsvc) gid=1005(backupsvc) groups=1005(backupsvc)
$ loginctl --no-pager --property=Name,User,State,Sessions show-user backupsvc

Warning: Do not substitute a production administrator's username just to test this. Lingering changes process lifetime and can keep user services running beyond the login that started them.

Enable it for the intended account. This is the first state-changing command in the guide:

$ sudo loginctl enable-linger backupsvc
$ loginctl --no-pager --property=Name,User,State,Sessions show-user backupsvc
Name=backupsvc
User=1005
State=offline
Sessions=

An offline user can still have a user manager because lingering is about the manager's lifetime, not about pretending the user is logged in. Verify the setting with the command's exit status and the user's manager or service, not by expecting an interactive session to appear.

Recovery: to undo this exact change, disable lingering for the same account:

$ sudo loginctl disable-linger backupsvc

Disabling lingering stops the automatic keep-alive behaviour. It is not a general-purpose stop command for every process already running under that user, so inspect the relevant user service separately if it must be stopped.

6. Handle destructive commands deliberately

Warning: terminate-session kills all processes in a session and releases its resources. terminate-user does the same for all sessions of a user, and terminate-seat affects every session on a seat. These are service-disrupting actions, not diagnostics:

$ loginctl --no-pager list-sessions
$ sudo loginctl terminate-session SESSION_ID

Before running one, check the ID immediately before the command, tell the user or service owner, and make sure you have a recovery path. There is no loginctl undo command for killed processes. Users must log in again, and services must be restarted through their normal service manager.

kill-session and kill-user are also destructive. Their default signal is SIGTERM; --kill-whom=all is the default for kill-session. Use --signal=SIGTERM explicitly when reviewing a command, and do not jump to SIGKILL merely because a process is inconvenient. If you only need to inspect state, return to show-session or show-user.

7. Avoid common loginctl traps

Done means