The Linux kernel writes its messages (hardware detection, driver events, filesystem errors, OOM kills) to an in-memory ring buffer. dmesg reads that buffer, and on systemd distributions journalctl -k reads the same messages from the journal, including those from previous boots. In this tutorial you will read and filter kernel messages on Ubuntu 24.04, follow them in real time, and learn to recognize the error patterns that point to failing disks, memory pressure and hardware faults.
Prerequisites
To follow this guide you need:
- A server running Ubuntu 24.04 LTS, for example a CubePath VPS. The commands also work on Debian 12 and Rocky Linux 9.
- A non-root user with
sudoprivileges.
dmesg is part of the util-linux package and journalctl is part of systemd, so there is nothing to install.
Step 1 - Reading the kernel ring buffer
Run dmesg as a regular user first:
dmesg
On Ubuntu this fails, because the kernel.dmesg_restrict setting limits the ring buffer to users with administrative privileges:
dmesg: read kernel buffer failed: Operation not permitted
You can confirm the setting with sysctl. A value of 1 means only root can read the buffer:
sysctl kernel.dmesg_restrict
kernel.dmesg_restrict = 1
Leave the restriction in place (kernel messages can reveal memory addresses useful to an attacker) and use sudo instead. Pipe the output to less so you can scroll through it:
sudo dmesg | less
[ 0.000000] Linux version 6.8.0-45-generic (buildd@lcy02-amd64-075) ...
[ 0.000000] Command line: BOOT_IMAGE=/vmlinuz-6.8.0-45-generic root=UUID=... ro
[ 0.012345] DMI: QEMU Standard PC (i440FX + PIIX, 1996), BIOS ...
[ 1.234567] virtio_net virtio1 ens18: renamed from eth0
The number in brackets is the time in seconds since the kernel started. The first lines describe the boot: the kernel version, the command line, the detected CPU, memory and devices. To see only the most recent messages, use tail:
sudo dmesg | tail -n 20
Step 2 - Making timestamps readable
Seconds since boot are hard to correlate with application logs. The -T option converts them to wall clock time:
sudo dmesg -T | tail -n 5
[Thu Sep 25 10:14:02 2026] EXT4-fs (sda1): re-mounted 3f1c...: filesystem is mounted read-write
[Thu Sep 25 10:14:03 2026] audit: type=1400 audit(...): apparmor="STATUS" operation="profile_load" ...
For logs you want to share or compare with other systems, the ISO 8601 format is unambiguous:
sudo dmesg --time-format iso | tail -n 5
2026-09-25T10:14:02,123456+00:00 EXT4-fs (sda1): re-mounted 3f1c...: filesystem is mounted read-write
The -H option (human readable) shows relative times between messages, adds colors and opens a pager automatically, which is handy for interactive reading:
sudo dmesg -H
Note
dmesg -Tcalculates the date from the current uptime. If the machine has been suspended, the converted times can be off. The journal (Step 5) stores the real time of each message and does not have this problem.
Step 3 - Filtering by log level and facility
Every kernel message has a priority level. These are the eight levels and the names dmesg accepts:
| Level | Name for dmesg -l | Meaning |
|---|---|---|
| 0 | emerg | System is unusable |
| 1 | alert | Action must be taken immediately |
| 2 | crit | Critical conditions |
| 3 | err | Error conditions |
| 4 | warn | Warning conditions |
| 5 | notice | Normal but significant condition |
| 6 | info | Informational |
| 7 | debug | Debug messages |
When you are troubleshooting, start with errors and anything more severe:
sudo dmesg -T -l emerg,alert,crit,err
On a healthy server this prints nothing or only a few known, harmless lines. Add warn to widen the search:
sudo dmesg -T -l emerg,alert,crit,err,warn
The ring buffer also contains messages written from user space (for example by systemd during early boot). The -k option limits the output to messages from the kernel itself, and -x prefixes each line with its facility and level so you can see why a message matched:
sudo dmesg -T -k -x -l err,warn
kern :warn : [Thu Sep 25 09:02:11 2026] ACPI: \_SB_.PCI0: _OSC: OS supports [...]
kern :err : [Thu Sep 25 09:02:12 2026] ata2.00: failed to IDENTIFY (I/O error, err_mask=0x4)
For keyword searches, combine dmesg with grep -i (case insensitive) and -E (several patterns):
sudo dmesg -T | grep -iE 'error|fail|oom|segfault'
Step 4 - Following new messages in real time
When you are reproducing a problem (plugging in a disk, loading a driver, running a workload that crashes), watch the kernel log as it happens with -w:
sudo dmesg -T -w
The command keeps running and prints new lines as the kernel logs them. Open a second SSH session and write a test message to the kernel log through /dev/kmsg. The <3> prefix gives the message the err level:
echo "<3>kmsg-test: this is a test error" | sudo tee /dev/kmsg
The first session shows the new line immediately:
[Thu Sep 25 10:20:45 2026] kmsg-test: this is a test error
Press CTRL+C to stop following. You can also follow only the severe messages with sudo dmesg -T -w -l err,crit,alert,emerg.
Step 5 - Reading kernel logs from previous boots with journalctl
The ring buffer has a fixed size and is lost on reboot, so after a crash or an unexpected restart dmesg cannot tell you what happened. On Ubuntu 24.04, systemd-journald copies every kernel message into the persistent journal under /var/log/journal. The -k option of journalctl shows only kernel messages:
sudo journalctl -k -b
-b limits the output to the current boot. List the boots the journal knows about:
sudo journalctl --list-boots
IDX BOOT ID FIRST ENTRY LAST ENTRY
-2 5c1e0f9d8b1a4f3e9e2a6c7b8d9e0f11 Mon 2026-09-15 08:00:12 UTC Mon 2026-09-22 03:14:55 UTC
-1 a7b3c2d1e0f94a8b9c7d6e5f4a3b2c1d Mon 2026-09-22 03:16:01 UTC Thu 2026-09-25 09:01:40 UTC
0 0e9d8c7b6a5f4e3d2c1b0a9f8e7d6c5b Thu 2026-09-25 09:02:05 UTC Thu 2026-09-25 10:21:30 UTC
To investigate why the server restarted, read the end of the kernel log from the previous boot:
sudo journalctl -k -b -1 -n 50
journalctl filters by priority with -p. The following command shows kernel errors and worse from the current boot, which is equivalent to dmesg -l emerg,alert,crit,err:
sudo journalctl -k -b -p err
You can also restrict the time range, which is useful when you know roughly when an incident happened:
sudo journalctl -k --since "2026-09-25 09:00" --until "2026-09-25 10:00"
The -g option searches message text with a regular expression (case insensitive when the pattern is all lowercase):
sudo journalctl -k -b -1 -g 'oom|i/o error|hardware error'
If /var/log/journal does not exist on your system, the journal is kept in memory only. Create the directory and restart journald to make it persistent:
sudo mkdir -p /var/log/journal
sudo systemctl restart systemd-journald
Step 6 - Recognizing common error patterns
Most kernel problems leave a recognizable signature. The commands below search the current boot with dmesg; replace sudo dmesg -T with sudo journalctl -k -b -1 to search the previous boot.
Out of memory (OOM) kills
When the system runs out of memory, the kernel OOM killer terminates a process to free memory:
sudo dmesg -T | grep -iE 'out of memory|oom-kill|killed process'
[Thu Sep 25 11:02:17 2026] oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,global_oom,task_memcg=/system.slice/myapp.service,task=python3,pid=4321,uid=1001
[Thu Sep 25 11:02:17 2026] Out of memory: Killed process 4321 (python3) total-vm:2861240kB, anon-rss:1843200kB, file-rss:0kB, shmem-rss:0kB, UID:1001 pgtables:3840kB oom_score_adj:0
The line tells you which process was killed, its PID and how much memory it used (anon-rss). task_memcg names the systemd unit it belonged to. Frequent OOM kills mean the workload needs more RAM, a memory limit, or a fix for a memory leak.
Disk and filesystem errors
Failing disks and controllers produce I/O errors, and filesystems report the corruption they detect:
sudo dmesg -T | grep -iE 'i/o error|ext4-fs error|xfs.*(error|corruption)|nvme.*(timeout|reset)|ata[0-9.]+: (exception|failed)'
[Thu Sep 25 12:40:03 2026] I/O error, dev sdb, sector 1953520 op 0x0:(READ) flags 0x80700 phys_seg 1 prio class 2
[Thu Sep 25 12:40:03 2026] EXT4-fs error (device sdb1): ext4_find_entry:1622: inode #2: comm ls: reading directory lblock 0
A few isolated errors after a cable or controller event may be transient, but repeated errors on the same device mean the disk should be replaced. Check its health with smartctl (package smartmontools) on physical servers, and take a backup before anything else. If ext4 hits an error it may remount the filesystem read-only, which you will see as Remounting filesystem read-only.
Hung tasks
A process stuck in uninterruptible I/O wait for too long triggers a warning with a stack trace:
sudo dmesg -T | grep -A 5 'blocked for more than'
[Thu Sep 25 13:05:41 2026] INFO: task jbd2/sda1-8:312 blocked for more than 122 seconds.
This usually points to very slow or unresponsive storage (an overloaded disk, a hung NFS mount) rather than a bug in the process itself.
Application crashes
When a user space program crashes, the kernel logs the segmentation fault and the library where it happened:
sudo dmesg -T | grep -i segfault
[Thu Sep 25 14:11:09 2026] myworker[5120]: segfault at 0 ip 00007f3a1c2b4d10 sp 00007ffd9a3c1e58 error 4 in libc.so.6[7f3a1c200000+195000]
Kernel bugs and oopses
A kernel bug or oops means the kernel itself hit an unexpected condition. The lines after the header, especially Call Trace, show which driver or subsystem was involved:
sudo dmesg -T | grep -A 30 -E 'BUG:|Oops:|WARNING: CPU:'
If the trace names a specific module (for example a network or storage driver), updating the kernel with sudo apt update && sudo apt full-upgrade and rebooting is the first thing to try.
Hardware errors on physical servers
On bare metal, CPU and memory errors are reported through the Machine Check Architecture (MCE) and the EDAC drivers:
sudo dmesg -T | grep -iE 'mce|machine check|hardware error|edac'
[Thu Sep 25 15:30:12 2026] mce: [Hardware Error]: Machine check events logged
[Thu Sep 25 15:30:12 2026] EDAC MC0: 1 CE memory read error on CPU_SrcID#0_Ha#0_Chan#1_DIMM#0 ...
CE means a corrected error: the ECC memory fixed it, but a growing number of them on the same DIMM is an early warning of failure. UE (uncorrected) errors usually crash the machine and require replacing the module. Virtual machines normally do not see these messages, because the hypervisor handles the hardware.
Network link changes
Physical NIC drivers log link state changes, which helps explain short connectivity drops:
sudo dmesg -T | grep -iE 'link is (up|down)'
[Thu Sep 25 16:01:55 2026] igb 0000:03:00.0 eno1: igb: eno1 NIC Link is Down
[Thu Sep 25 16:01:58 2026] igb 0000:03:00.0 eno1: igb: eno1 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: RX/TX
Troubleshooting
Old messages are missing from dmesg. The ring buffer is circular, so on a busy or long-running system the oldest boot messages are overwritten. Read them from the journal with sudo journalctl -k -b, which keeps the full boot. To enlarge the buffer itself, add log_buf_len=4M to GRUB_CMDLINE_LINUX_DEFAULT in /etc/default/grub, then run sudo update-grub and reboot.
The same message floods the console. Kernel messages at or above the console log level are also printed to the physical or serial console. Lower it so only errors and worse reach the console, without affecting what is recorded in the buffer or the journal:
sudo dmesg -n err
The times from dmesg -T do not match other logs. dmesg -T uses the local time zone and derives the date from uptime. Check the time zone with timedatectl, and use journalctl -k, which stores the real timestamp of each message, when precise correlation matters.
You cleared the buffer by accident. dmesg -c and dmesg -C empty the ring buffer. The messages are still in the journal, so sudo journalctl -k -b shows them. Avoid those options on production servers.
Conclusion
You can now read the kernel ring buffer with dmesg, make its timestamps readable, filter by level, follow events live and use journalctl -k to investigate previous boots. The error signatures above (OOM kills, I/O errors, hung tasks, MCE/EDAC reports) are the first things to check when a server misbehaves or restarts unexpectedly.
As next steps, you can monitor disk health with smartmontools, set memory limits on your services with systemd MemoryMax= to keep a single process from triggering the OOM killer, and forward the journal to a central log server so kernel errors from all your machines are searchable in one place.
