Skip to main content

Linux command: journalctl

24 July 2026

Something breaks on a Linux server. A website will not start, a backup fails at night, a service dies for no clear reason. On almost every modern Linux system, the first command that answers "what just happened?" is journalctl. It reads the systemd journal, a single searchable record of nearly everything the system and its services have said since boot. Where older systems scattered logs across a dozen text files in /var/log, systemd collects them in one place, and journalctl is the tool you use to ask that record questions.

1. The Basics

The job of journalctl is to read and filter the systemd journal. The journal is a structured log kept by a background service called systemd-journald. Every message from the kernel, from systemd itself, and from every service it starts flows into that journal. journalctl is the window you look through to see it.

This matters because it changes how you troubleshoot. On an old system you had to know which file to open: /var/log/syslog for general messages, /var/log/auth.log for logins, a separate file per application. With the journal, you ask one tool and narrow down from there:

The old wayThe journal way
Guess which file in /var/log holds the message One command, then filter by service, time, or priority
Plain text files, easy to read but unstructured Structured entries with dozens of indexed fields
Combine files by hand to see the full timeline Kernel, services, and apps already merged in order

One record for the whole system, and one command to question it: by service, by boot, by time, or by how serious the message is.

This article starts with the plainest use and builds up step by step to filtering by unit and boot, priority levels, the structured fields under each line, output formats, and how to keep the journal from filling your disk. By the end, reading logs on a systemd machine will feel routine.

The right mental model: the journal is a database of log entries, not a text file. journalctl is the query tool. Every line you see on screen is really a record with many fields, and the plain output is just one friendly view of it.

1.1 The Simplest Possible Use

Run journalctl with no options and it prints the entire journal, oldest first, into a pager:

$ journalctl
-- Journal begins at Wed 2024-05-01 09:12:04 CEST. --
May 01 09:12:04 xps kernel: Linux version 6.8.0-50-generic ...
May 01 09:12:04 xps kernel: Command line: BOOT_IMAGE=/boot/vmlinuz ...
...

The output opens in less, so you can scroll, and search with /, just like reading a file. Press q to quit. On a machine that has been running for weeks this can be a very long list, which is why the next sections are all about narrowing it down.

1.2 You Usually Need root

A normal user sees only their own user services and, on many systems, a limited view. To read the full system journal, run it with sudo:

$ sudo journalctl

On most distributions, adding your account to the systemd-journal group grants read access to the whole journal without sudo each time. Membership takes effect at your next login.

Back to top

2. Where the Name Comes From

The name is two parts joined together: journal plus ctl.

journalctl  =  JOURNAL + con-TROL

The journal is systemd's name for its log store. The word fits: like a ship's log or a diary, it is an ordered record of events written down as they happen, and never rewritten out of order.

The ctl ending is short for control, and it is a house style across the whole systemd family. Once you spot the pattern, a long list of tool names suddenly makes sense:

CommandControls
systemctl services and units
journalctl the journal (logs)
hostnamectl the system hostname
timedatectl time, date, and time zone
loginctl user logins and sessions

So journalctl reads as "the control program for the journal". It is a query and management tool, even though reading logs is what you will use it for ninety percent of the time.

Back to top

3. A Short History

To understand journalctl you have to know where it came from, because it replaced a way of logging that had barely changed for decades.

For most of Unix history, logging was done by syslog: a service (such as syslogd or later rsyslog) received messages and appended them as lines of text to files under /var/log. It was simple, human-readable, and easy to process with grep, awk, and friends. Its weakness was structure: a log line was just a string, so filtering by service, user, or exact time meant parsing text and hoping every program formatted its lines the same way.

systemd, first released in 2010 by Lennart Poettering and Kay Sievers, set out to replace the old init system that started services at boot. A couple of years later the project added its own logging service, systemd-journald, and with it the journalctl tool. Instead of plain text, the journal stores each entry as a set of key/value fields in an indexed binary file, so filtering and sorting are built in.

EraMilestone
1980s syslog appears in BSD Unix; text log files in /var/log become the standard
2010 systemd is released and starts to replace older init systems on Linux
~2012 systemd-journald and journalctl introduce the structured binary journal
Today Most mainstream distributions (Debian, Ubuntu, Fedora, RHEL, Arch, SUSE) use the journal by default

The journal did not fully kill syslog. Many systems run rsyslog alongside the journal, forwarding entries so that classic text files still exist for tools and habits that expect them. But on a default modern install, journalctl is the primary way to read logs. This article is verified against systemd version 255.

Back to top

4. Simple Use Cases

4.1 Jump to the Newest Messages: -e

Most of the time you do not want the start of the journal, you want the end, where the latest events are. The -e flag (short for pager-end) opens the pager already scrolled to the bottom:

$ journalctl -e

This is often the very first thing you run: open the log, land on the newest lines, scroll up to see what led to the problem.

4.2 Show Only the Last N Lines: -n

The -n flag (short for lines) prints just the most recent entries, like tail on a normal file. On its own it shows the last 10:

$ journalctl -n         # the last 10 entries
$ journalctl -n 50      # the last 50 entries

Unlike the full view, -n prints straight to your terminal without the pager, so it is perfect for a quick glance or inside a script.

4.3 Follow New Messages Live: -f

The -f flag (short for follow) keeps the command running and prints each new entry the moment it arrives. It is the journal's version of tail -f:

$ journalctl -f
-- Waiting for new entries --
Sep 24 08:58:47 xps systemd[1]: Started daily cleanup of temporary files.
...

You leave this open in one terminal while you reproduce a problem in another, and watch the log react in real time. Press Ctrl+C to stop following.

4.4 Newest First: -r

The -r flag (short for reverse) shows the entries with the newest at the top instead of the bottom:

$ journalctl -r         # most recent entry printed first

This pairs well with -n when you only care about the last thing that happened and do not want to scroll to the end of a pager.

Back to top

5. Moderate Use Cases

5.1 Logs for One Service: -u

This is the single most useful filter. The -u flag (short for unit) limits the output to one systemd unit, such as a web server or database:

$ journalctl -u nginx.service
$ journalctl -u ssh            # the .service suffix is optional

Combine it with the flags you already know to get a sharp, practical view:

$ journalctl -u nginx -n 50      # last 50 lines for nginx
$ journalctl -u nginx -f         # follow nginx live

Instead of hunting for the right log file, you name the service and see exactly its messages, merged in time order.

5.2 Filter by Time: --since and --until

The --since (-S) and --until (-U) options limit the output to a time window. They accept exact timestamps and friendly words:

$ journalctl --since "2026-07-12 09:00:00"
$ journalctl --since "1 hour ago"
$ journalctl --since yesterday --until "09:00"
$ journalctl -u nginx --since today

Words like today, yesterday, and phrases like 10 min ago are understood directly. This is how you answer "what happened around the time the site went down?" without scrolling through days of history.

5.3 Only This Boot: -b

A server may have restarted several times. The -b flag (short for boot) limits the journal to a single boot. With no number it means the current boot:

$ journalctl -b          # everything since the last boot
$ journalctl -b -1       # the previous boot
$ journalctl --list-boots

The last command lists every boot the journal remembers, with an index and a time range:

$ journalctl --list-boots
IDX BOOT ID           FIRST ENTRY                  LAST ENTRY
 -2 8b909d28e49e4884  Sat 2026-06-20 10:20:39 CEST Sat 2026-06-20 15:35:36 CEST
 -1 6f4e7bd5d6ea468f  Sat 2026-06-20 15:36:13 CEST Sat 2026-06-20 16:24:37 CEST
  0 c62bfe02a8b64075  Sun 2026-06-21 13:28:43 CEST Sun 2026-06-21 15:19:26 CEST

The current boot is always 0, and older boots count down with negative numbers. This is how you check "did anything go wrong before the last reboot?".

5.4 Filter by Severity: -p

Not every message matters equally. The -p flag (short for priority) keeps only entries at or above a level of seriousness. The journal uses the eight classic syslog levels:

NumberNameMeaning
0 emerg System is unusable
1 alert Action must be taken immediately
2 crit Critical condition
3 err Error
4 warning Warning
5 notice Normal but notable
6 info Informational
7 debug Debug-level detail

Ask for a level by name or number, and you get that level and everything more serious:

$ journalctl -p err          # errors, crit, alert, emerg only
$ journalctl -p warning -b    # warnings and worse, this boot

Filtering to err and above is a fast way to cut a noisy log down to the entries that usually deserve attention. You can also give a range in the form FROM..TO to pin the output to a band of levels and leave out the rest:

$ journalctl -p err..alert    # only err, crit, and alert (not emerg, not warning)

5.5 Kernel Messages: -k

The -k flag (short for dmesg, the traditional kernel-message command) shows only messages from the kernel itself, for the current boot:

$ journalctl -k          # like dmesg, but from the journal

This is where you look for hardware trouble: a failing disk, a network card resetting, or an out-of-memory event.

5.6 Investigating a Crash: Boot IDs as Anchors

When you look into an unexpected reboot or a security incident, the boot becomes your unit of investigation, and the Boot ID is what anchors it. Every time the machine starts, the kernel assigns a fresh, unique 32-character identifier, and the journal stamps every entry of that session with it in the _BOOT_ID field. Because the ID is fixed for the whole boot, it identifies a session reliably even if the clock jumps or files are rotated, which the wall-clock time alone cannot promise.

You saw the relative index earlier (-b -1 for the previous boot). For evidence you often want the exact boot instead, named by its ID from --list-boots:

$ journalctl -b 6f4e7bd5d6ea468f9b1cbe30f800c32d    # one exact boot, by its ID

The real power comes from combining the boot filter with the others you already know, to ask a sharp question about a single session. To investigate the boot before a crash:

$ journalctl -b -1 -k -p err       # kernel errors from the previous boot
$ journalctl -b -1 -p err          # all errors and worse, previous boot
$ journalctl -b -1 -u sshd         # who touched ssh before the reboot

This is the everyday shape of log forensics: pick the boot, then narrow by the kernel, a priority, a service, or a time window until only the relevant lines remain. Boot IDs make "what happened during that one session?" a precise query rather than a scroll through a merged timeline.

Back to top

6. Advanced Use Cases

6.1 Matching Fields Directly: KEY=VALUE

Under the friendly output, every journal entry is a set of fields. You can filter on any of them by passing FIELD=VALUE as a plain argument. This is the real power behind flags like -u, which is just a shortcut for matching the unit field:

$ journalctl _SYSTEMD_UNIT=nginx.service
$ journalctl _PID=1249                 # one process by its PID
$ journalctl _UID=1000                 # everything from one user account
$ journalctl _COMM=sshd                # by program (command) name

Fields whose names start with an underscore, such as _PID and _UID, are "trusted" fields: the journal adds them itself from the kernel, so a program cannot fake them. To discover which fields and values exist, ask the journal:

$ journalctl -N                        # list all field names in use
$ journalctl -F _SYSTEMD_UNIT          # list all values a field takes

A neat shortcut: pass the path to a program as an argument, and the journal turns it into the right field match for you. For an executable binary it adds an _EXE= match, and for a script an _COMM= match:

$ journalctl /usr/sbin/sshd            # same as _EXE=/usr/sbin/sshd
$ journalctl /usr/bin/bash             # everything logged by bash

6.2 Search the Message Text: -g

The -g flag (short for grep) filters entries whose message matches a regular expression. By default the match is case-insensitive unless the pattern contains an uppercase letter:

$ journalctl -g "failed|denied"        # any message mentioning either word
$ journalctl -u ssh -g "invalid user"  # failed logins for ssh

This searches inside the journal much faster than piping everything through an external grep, because the journal handles the filtering itself.

6.3 Combining Matches: AND, OR, and Reset

How several filters combine follows a small set of rules that are worth knowing:

  • Different fields are joined with AND. journalctl -u nginx -p err means "nginx AND at least error level".
  • The same field given twice is joined with OR. journalctl _SYSTEMD_UNIT=nginx.service _SYSTEMD_UNIT=php-fpm.service shows either service.
  • A + on its own combines two whole groups with OR.
$ journalctl -u nginx.service + -u php-fpm.service
# nginx entries OR php-fpm entries

6.4 Changing the Output Format: -o

The -o flag (short for output) changes how each entry is printed. The default is short, close to a classic syslog line. Other formats reveal more or feed other tools:

FormatWhat you get
short The default, one line per entry
short-iso Same, but with full ISO timestamps
verbose Every field of every entry, in full
cat Only the message text, no timestamp or host
json One JSON object per entry, for scripts
json-pretty The same JSON, indented for reading
$ journalctl -u nginx -o json-pretty -n 1
$ journalctl -o cat -u nginx           # bare messages, no clutter

The json formats are the bridge to other software: you can pipe them into jq or a log-collection system and process the fields exactly.

6.5 Explanations for Known Messages: -x

The -x flag (short for catalog) adds a longer explanation under messages that systemd recognises, drawn from a built-in message catalog. It is very common to see the pair -xe:

$ journalctl -xe          # jump to the end, with explanations added

For a failing service this can add a paragraph describing what the message means and what to check, which is a real help when the raw line is cryptic.

6.6 System and User Journals: --user

The journal is really two streams. The system journal holds the kernel and system services; a separate user journal holds the services that run under your own login (the things systemd starts for you, such as a desktop session or a user timer). By default journalctl shows the system journal, but two flags pick the stream explicitly:

$ journalctl --system         # the system journal (the default)
$ journalctl --user           # only your own user services
$ journalctl --user -u myapp  # one of your user units

This explains a common confusion: a service you started with systemctl --user start myapp will not appear under a plain sudo journalctl -u myapp, because it lives in the user journal. Reach for --user when the logs you expect are missing from the system view.

Back to top

7. Something Most Users Do Not Know

7.1 Every Line Is Really a Record with Many Fields

The plain journalctl output looks like text, but each entry is stored as a bundle of fields. Ask for the verbose format and one single line unfolds into everything the journal knows about it:

$ journalctl -n 1 -o verbose
Thu 2026-09-24 08:58:47.550521 CEST [s=f6a6...;i=26de0c;b=84ee...]
    PRIORITY=6
    _HOSTNAME=xps
    _UID=0
    _GID=982
    _PID=1249
    _COMM=nordvpnd
    _EXE=/usr/sbin/nordvpnd
    _SYSTEMD_UNIT=nordvpnd.service
    _BOOT_ID=84ee2a04d2c94a348d1a43b1d1c09db4
    SYSLOG_IDENTIFIER=nordvpnd
    MESSAGE=HTTP call finished in 240ms

This is the heart of what makes the journal different from a text log. The program supplied the MESSAGE, and the journal attached the rest automatically: which process, which user, which service, which boot. Because those fields are indexed, filtering by any of them is fast and exact, with no text parsing.

A syslog file remembers the sentence. The journal remembers the sentence, who said it, when, on which boot, from which process, and under which service, all as separate fields you can query.

7.2 The Journal Can Be Volatile: Logs May Vanish on Reboot

Here is a surprise that catches many people out. Whether your logs survive a reboot depends on a directory existing:

  • If /var/log/journal/ exists, the journal is persistent: it is written to disk and kept across reboots.
  • If that directory does not exist, the journal is volatile: it lives only in memory under /run/log/journal/ and is wiped on every reboot.

On some minimal systems the default is volatile, which means journalctl -b -1 for a past boot returns nothing, because that boot's logs were never saved. The setting is controlled by Storage= in /etc/systemd/journald.conf. To guarantee persistent logs, make sure the directory exists and let journald flush to it:

$ sudo mkdir -p /var/log/journal
$ sudo systemctl restart systemd-journald

This one difference explains a common frustration: "I rebooted to fix it and now the evidence is gone." On a server you care about, persistent storage should always be on.

7.3 Monotonic Timestamps Survive a Clock Change

The timestamps you normally see are wall-clock time, and wall-clock time can jump. When NTP corrects the clock, or an administrator sets it by hand, the ordinary log times shift with it, which can scramble the apparent order of events. The journal also records a monotonic timestamp: seconds since the machine booted, which only ever counts forward. Ask for it with the short-monotonic output format:

$ journalctl -b -o short-monotonic
[   12.345678] xps systemd[1]: Started NetworkManager.
[   15.892134] xps nginx[812]: nginx.service started.
[   18.456201] xps sshd[1123]: Accepted publickey for peter

The number in brackets is the elapsed time since boot. Because it cannot move backwards, it gives a trustworthy order of events even across a clock adjustment, which makes it the format of choice when you reconstruct exactly what happened during a boot or an incident. It pairs naturally with the Boot ID from section 5.6: the Boot ID picks the session, and the monotonic clock fixes the order of events inside it, even when the wall clock cannot be trusted.

7.4 The Journal Can Be Sealed, But It Is Not Encrypted

Two facts about the journal's safety surprise people, and both are worth knowing:

  • The journal is not encrypted by default. Binary storage stops casual editing with a text editor, but anyone who can read the files can read the messages. Do not treat it as a place to hide secrets.
  • The journal can be tamper-evident. A feature called Forward Secure Sealing (FSS) periodically signs the journal with a key, so that later changes to old entries can be detected. You turn it on by generating a key pair:
$ sudo journalctl --setup-keys      # generate an FSS key pair
$ journalctl --verify               # check the journal for tampering

Sealing does not hide the contents; it proves whether they were altered after the fact. That distinction matters on a machine where the logs may become evidence: FSS answers "has this log been changed?", not "can others read it?".

7.5 Where journalctl Stops, Other Tools Take Over

The journal reads its own store, and that is where it ends. A few neighbours pick up from there:

  • systemctl status nginx shows a unit's state and its last few journal lines together, which is often enough to start.
  • dmesg reads the kernel ring buffer directly; journalctl -k shows the same messages through the journal.
  • rsyslog still writes classic text files in /var/log on many systems, useful for tools that expect them.
  • For many machines, a central log collector (such as an ELK or Loki stack) ingests the journal's JSON output so you can search all servers at once.

Knowing this boundary keeps you efficient: journalctl for one machine's history, a collector when you need many machines in one view.

Back to top

8. Best Practices

  • Filter before you scroll. Reach for -u service, -b, --since, and -p err early. Narrowing the query beats reading a wall of text.
  • Learn the -xe reflex. When a service fails, journalctl -xe -u name jumps to the end, filters to that unit, and adds explanations in one step.
  • Turn on persistent storage. Make sure /var/log/journal/ exists so logs survive reboots, otherwise a restart erases the evidence you need.
  • Cap the journal's size. Set SystemMaxUse= in /etc/systemd/journald.conf, or run a vacuum, so logs never fill the disk (see section 9).
  • Check disk use now and then. journalctl --disk-usage tells you how much space the journal occupies.
  • Prefer field matches for precision. _PID=, _UID=, and _SYSTEMD_UNIT= filter exactly, with no risk of a text pattern matching the wrong line.
  • Read the manual when unsure. The behaviour is fully documented; man journalctl and man journald.conf are the reference.
$ man journalctl        # the command and all its options
$ man journald.conf     # storage, size limits, and rotation
$ journalctl --help     # a quick summary of the flags
Back to top

9. Common Mistakes

9.1 Myth versus Reality

MythReality
"The journal is just text files in /var/log." It is an indexed binary store. You read it with journalctl, not with cat or tail on the files.
"Logs are always kept after a reboot." Only if /var/log/journal/ exists. Otherwise the journal is in memory and is wiped on reboot.
"journalctl -u nginx also shows nginx's own access log." It shows what nginx sent to the journal (mostly startup and errors). Access logs written to nginx's own files are separate.
"-p err shows only errors." It shows that level and everything more serious (crit, alert, emerg too).
"The journal manages its own size, so I can ignore it." It has limits, but on a busy server they can be large. Check with --disk-usage and set a cap.

9.2 Other Traps to Avoid

  • Reading only the current boot by accident. Many examples use -b, which hides older boots. Drop -b, or use -b -1, when you need history from before the last restart.
  • Forgetting sudo. As a normal user you may see only part of the journal. Use sudo, or join the systemd-journal group, to read everything.
  • Letting the journal fill the disk. If space runs low, clear old entries safely with a vacuum rather than deleting files by hand:
$ sudo journalctl --vacuum-size=500M    # keep at most 500 MB
$ sudo journalctl --vacuum-time=2weeks   # delete entries older than 2 weeks
  • Piping to grep when a flag is better. journalctl | grep nginx works but is slow and clumsy. journalctl -u nginx or -g pattern lets the journal filter for you.
  • Expecting local time in scripts. Timestamps show your local time zone by default. Add --utc when you need a stable, comparable time across servers.
  • Not knowing that journald drops messages under load. To protect itself from a flood, journald rate-limits each service (by default 10000 messages in 30 seconds) and then writes a note that it "Suppressed" the rest. If a very chatty service seems to be missing lines, it may have hit that limit, not failed. Raise RateLimitBurst= in /etc/systemd/journald.conf if you truly need every line.
Back to top

10. Summary

The journalctl command is the front door to logs on any modern Linux system. Learn a handful of filters and most troubleshooting becomes a short, targeted query instead of a hunt through files.

  • journalctl reads the systemd journal, one structured record of the whole system's messages.
  • The name means "journal control", part of the systemd family alongside systemctl and timedatectl.
  • It replaced plain syslog text files with an indexed binary store, arriving with systemd around 2012.
  • Use -e to jump to the end, -n for the last lines, -f to follow live, and -r for newest first.
  • Filter by service with -u, by time with --since and --until, by boot with -b, by severity with -p, and to the kernel with -k.
  • Every entry is a set of fields; match them directly with _PID=, _UID=, _SYSTEMD_UNIT=, and search text with -g.
  • Change the view with -o (including json for scripts and short-monotonic for a clock-proof order) and add explanations with -x.
  • The journal has two streams: the system journal and, with --user, your own user services.
  • Logs survive a reboot only when /var/log/journal/ exists; keep the size in check with --disk-usage and --vacuum-*.
  • The journal is not encrypted by default, but Forward Secure Sealing (--setup-keys, --verify) can make it tamper-evident.

This is the quick reference worth keeping:

journalctl -e                 open the log at the newest entries
journalctl -n 50              show the last 50 entries
journalctl -f                 follow new entries live
journalctl -u nginx           logs for one service
journalctl -u nginx -f        follow one service live
journalctl -b                 only the current boot
journalctl -b -1              the previous boot
journalctl -b -1 -k -p err    kernel errors from the previous boot
journalctl --list-boots       list recorded boots
journalctl --since "1 hour ago"   filter by time
journalctl -p err             errors and worse only
journalctl -p err..alert      a range of priority levels
journalctl -k                 kernel messages (like dmesg)
journalctl --user             your own user services
journalctl -g "pattern"       search message text
journalctl -o short-monotonic clock-proof order (seconds since boot)
journalctl -xe -u name        end of a unit's log, with explanations
journalctl --disk-usage       how much space the journal uses
sudo journalctl --vacuum-time=2weeks   trim old entries

Reading logs well is one of the quiet skills that separates a calm server administrator from a stressed one: the difference between knowing exactly why a service failed at 3am and only guessing. If your servers keep logs that vanish on reboot, fill the disk, or never quite answer the question when something breaks, it pays to have the journal set up properly before the next incident, so the evidence is there when you need it.

Back to top
Linux command: journalctl
Peter Martin
Peter Martin
Joomla Specialist

Peter is a Joomla specialist and a Linux admin for fast, secure and scalable websites.