When something goes wrong at the hardware or driver level on a Linux system, dmesg is where you look first. It exposes the kernel ring buffer -- a fixed-size circular log maintained by the kernel itself, written to before any userspace logging daemon is running. That means it captures everything from the moment the kernel starts: memory detection, CPU topology, driver initialization, USB device plug events, disk errors, and kernel panics.
This article is a practical quick-reference. It covers the flags you'll actually use, how to filter signal from noise, how to work with timestamps correctly, and what common kernel messages are telling you.
What Is the Kernel Ring Buffer?
The kernel maintains a fixed-size in-memory buffer where it writes diagnostic messages. Because it is circular, once it fills up, older messages are overwritten by newer ones. On a busy system, or one that has been up for a long time, early boot messages may have already been rotated out.
The dmesg command reads this buffer and prints it to stdout. On modern Linux systems using systemd-journald, kernel messages are also captured by the journal -- which means journalctl -k can give you persistent access to kernel messages even after the ring buffer has rotated. But dmesg remains the fastest way to get there, and it works even on systems without systemd.
The upstream Linux kernel default for kernel.dmesg_restrict is 0 (unrestricted). However, many distributions -- including Ubuntu, Debian, and Fedora -- set it to 1 via their hardening configurations. When the value is 1, reading the ring buffer requires the CAP_SYSLOG capability. Use sudo dmesg to ensure you get the full output regardless of which setting is active. This feature has been available since kernel 2.6.37 (Linux Kernel Documentation, kernel.txt). On systems with multiple users or shared access, it is worth reviewing Linux user permissions and privilege misconfigurations alongside this setting.
Essential Flags
Raw dmesg output is readable but rarely comfortable. These flags make it usable.
Human-Readable Timestamps
By default, each message is prefixed with seconds elapsed since boot -- not a real clock time. On a system that has been running for weeks, that number is nearly meaningless. Use -T to convert it to wall-clock time:
The output now shows a proper date and time for each message. Combine with | less for comfortable scrolling through long output.
The -T timestamps are computed by combining the kernel's monotonic clock offset with the current wall time at the moment dmesg runs. The monotonic clock does not advance during system suspend -- it pauses. The wall clock keeps running. On a laptop or workstation that has been suspended and resumed many times over a long uptime, the accumulated divergence can render -T timestamps days off from reality, not just minutes. A machine with 18 days of uptime and significant suspend history can show messages timestamped days in the future. -T is only reliable for messages generated since the last resume. For any investigation where timestamp accuracy matters -- incident correlation, forensics, multi-system log comparison -- use journald, which records wall-clock time at ingestion and is not affected by suspend gaps. Raw monotonic output (default, no -T) remains internally consistent and is preferable for scripted analysis (source: util-linux dmesg man page).
Follow Mode
To watch new kernel messages in real time -- for example, while plugging in a USB device or loading a driver -- use -w (or --follow):
This is the kernel equivalent of tail -f on a syslog file. The terminal stays open and prints new messages as they arrive. Press Ctrl+C to exit.
Filter by Time Window with --since
On systems with util-linux 2.36 or later, --since limits output to messages after a specified time, using either an absolute timestamp or a relative expression:
# Show messages from the last hour only $ sudo dmesg -T --since '1 hour ago' # Show messages since a specific timestamp $ sudo dmesg -T --since '2026-04-09 03:00'
This is more precise than piping through grep for a time range and avoids the ambiguity of seconds-since-boot values. Combine with -l err,warn to narrow to errors within a specific window.
Watch for New Messages Only with -W
While -w / --follow prints the full existing buffer before entering follow mode, -W / --follow-new (util-linux 2.36+) skips the existing buffer and prints only messages that arrive after the command is invoked. This is the right choice when you want a clean capture of a hardware event without first wading through accumulated output:
Trigger your event -- plug in a device, load a module, mount a filesystem -- then press Ctrl+C to stop. Everything printed is directly associated with what you just did.
Filter by Log Level
The kernel assigns each message a log level from 0 (emergency) to 7 (debug). Use -l to filter by one or more levels:
# Show only errors and critical messages $ sudo dmesg -T -l err,crit # Show only warnings $ sudo dmesg -T -l warn # Show everything at notice level and above (0-5) $ sudo dmesg -T -l emerg,alert,crit,err,warn,notice
The available log levels, from highest to lowest severity, are: emerg, alert, crit, err, warn, notice, info, and debug. On a healthy system, you should see nothing at emerg or alert. Regular err messages often indicate driver problems or hardware failures worth investigating.
A less commonly documented feature: appending a + to a level name includes all higher-severity levels automatically. This means sudo dmesg -T -l err+ prints err, crit, alert, and emerg in a single flag -- equivalent to listing all four explicitly. Prepending + includes all lower-severity levels instead: -l +warn prints everything from warn down through debug. This syntax is available in util-linux and is documented in the man page but not widely known (source: util-linux dmesg man page).
# err+ means: err, crit, alert, emerg -- all higher-severity levels in one flag $ sudo dmesg -T -l err+ # +warn means: warn, notice, info, debug -- warn and all lower-severity levels $ sudo dmesg -T -l +warn
sudo dmesg -T -l emergsudo dmesg -T -l alertsudo dmesg -T -l crit. For triage, combine: -l emerg,alert,crit,errsudo dmesg -T -l errsudo dmesg -T -l warnsudo dmesg -T -l noticesudo dmesg -T -l infodebug=1 or dyndbg is active for a subsystem. If you see a flood of these unexpectedly, check whether debug logging was enabled during a previous session. Filter: sudo dmesg -T -l debugISO Timestamp Format
For cross-system log comparison or machine parsing, --time-format iso outputs timestamps in ISO 8601 format with microsecond precision and timezone offset: YYYY-MM-DD<T>HH:MM:SS,<microseconds><+/-><timezone>. This is particularly useful when correlating dmesg output from multiple machines or piping into log aggregation tools:
# ISO 8601 with microseconds and timezone offset -- machine-parseable $ sudo dmesg --time-format iso -l err+ # ISO format has the same suspend/resume inaccuracy as -T # Use raw monotonic output for internally consistent scripting $ sudo dmesg --time-format raw -l err+
Show Time Between Messages with --show-delta
The -d / --show-delta flag prints the elapsed time between each consecutive kernel message, alongside the timestamp. This is the right tool for boot performance analysis -- it reveals which driver or subsystem caused a multi-second stall during probe:
# Show the delta (time elapsed since the previous message) alongside each entry $ sudo dmesg -d # Combine with -T to see wall-clock time AND the per-message delta $ sudo dmesg -Td # Filter to errors only, with deltas -- useful for spotting timeout durations $ sudo dmesg -Td -l err+
The delta format appends a time elapsed field in microseconds after each timestamp. A 30-second delta on a driver probe line is an immediate indicator of a hardware timeout -- the kernel waited the full timeout period for a device that never responded. This pattern is common with missing NIC firmware, unresponsive storage controllers, and stalled ACPI table evaluation. Without -d, the gap is invisible unless you manually subtract timestamps.
The --time-format flag accepts multiple values on one invocation -- for example, --time-format ctime --time-format delta emits both the wall-clock time and the per-message delta on the same line. The delta always follows the ctime or raw format when combined this way (source: util-linux dmesg man page).
JSON Output and Machine-Parseable Formats
For log pipelines, alerting scripts, or any tooling that consumes dmesg programmatically, --json (available in util-linux 2.37 and later) outputs each ring buffer record as a JSON object. Timestamps in JSON mode are emitted as sec.usec floating-point values only -- -T and other time-format flags are silently ignored when --json is active:
# JSON output -- each record is a structured object with sec.usec timestamps $ sudo dmesg --json | python3 -m json.tool | head -40 # --decode (-x) rewrites numeric facility/level prefixes as human-readable text # Output: kern:err instead of raw numeric prefix bytes $ sudo dmesg -x -l err+ # Combine JSON with --decode to split facility and priority into readable fields $ sudo dmesg --json --decode -l err+
The --decode / -x flag rewrites the numeric log-level prefix embedded in raw output into a human-readable facility:level pair such as kern:err. Without --decode, a raw record shows a numeric prefix like <3>, where 3 is KERN_ERR. The number encodes both facility and priority in a single byte: level = prefix & 7, facility = prefix >> 3. Understanding this encoding matters when parsing dmesg output from saved log files or ring buffer dumps taken from another machine.
Printing Userspace Messages and Injecting Sentinels
Since kernel 3.5.0, processes with appropriate privileges can write messages directly to /dev/kmsg, injecting them into the kernel ring buffer alongside actual kernel messages. The -u / --userspace flag filters dmesg output to show only these userspace-originated messages, excluding kernel messages entirely:
# Show only messages written by userspace processes to /dev/kmsg $ sudo dmesg -T --userspace # Inject a sentinel marker into the ring buffer from a shell script # Marks test boundaries: everything after this line is from your test run $ echo "TEST_START: firmware_probe_test" | sudo tee /dev/kmsg # The marker will appear in dmesg output; use --decode to confirm its facility $ sudo dmesg -T -x | grep TEST_START
Injecting a sentinel into /dev/kmsg before reproducing a hardware issue gives you a precise correlation point in the ring buffer. Everything after the sentinel in dmesg output occurred after your marker was written. This is particularly useful when investigating flaky hardware: write a sentinel, trigger the event, then isolate with sudo dmesg -T --since from the sentinel's timestamp. One constraint to know: it is not possible to inject messages with facility LOG_KERN (0) from userspace -- the kernel enforces this so that message origin can always be determined (source: Linux Kernel Documentation, dev-kmsg).
How dmesg Reads the Ring Buffer
Since kernel 3.5.0, dmesg reads from /dev/kmsg by default rather than the older syslog(2) syscall. The /dev/kmsg character device provides structured per-record access to the kernel printk buffer, including facility, level, sequence number, and timestamp as separate fields. You can read raw records directly with dd if=/dev/kmsg iflag=nonblock -- the output format is different from what dmesg displays after formatting, but it exposes the underlying data structure. Use sudo dmesg -S (or --syslog) to force the legacy syslog(2) interface if needed for compatibility.
This distinction matters when dmesg is not available -- for example, in a minimal recovery environment or a container without the util-linux package. In those cases, reading /dev/kmsg directly is a viable fallback.
/dev/kmsg vs /proc/kmsg -- the Single-Consumer Trap
There are two kernel interfaces for reading the ring buffer and they behave very differently. /dev/kmsg (since kernel 3.5.0) is a character device that supports multiple simultaneous readers, exposes structured records with sequence numbers, and is non-destructive -- reading it does not advance any shared read pointer. /proc/kmsg is a destructive stream: reading it advances the kernel's internal read pointer and consumes entries. Only one process can meaningfully consume /proc/kmsg at a time. If a syslog daemon (klogd, rsyslog, syslog-ng) is already reading /proc/kmsg, attempting cat /proc/kmsg will either block or produce incomplete output, and messages seen by one reader are not seen by the other.
# See which processes currently have /dev/kmsg open # systemd and systemd-journald normally hold read/write handles on it $ sudo lsof /dev/kmsg # Force dmesg to use the legacy syslog(2) interface instead of /dev/kmsg # Useful on older kernels or stripped-down environments $ sudo dmesg -S # Read raw /dev/kmsg records directly (non-blocking, structured format) # Output format differs from dmesg -- includes sequence number, facility/level prefix $ dd if=/dev/kmsg iflag=nonblock 2>/dev/null | head -20
The sequence number in each /dev/kmsg record is a monotonically increasing counter. A gap in sequence numbers between two consecutive records means messages were overwritten by the circular buffer before you read them. This is a precise indicator that the ring buffer filled and rotated -- not just that output was filtered. If you see sequence gaps on a busy server, consider increasing the ring buffer size at next boot using the log_buf_len kernel parameter.
Console Log Level and /proc/sys/kernel/printk
The ring buffer receives all kernel messages regardless of log level. Separately, the kernel decides which messages to also print to the active console (tty) in real time, controlled by console_loglevel. Any message with a priority higher than the console loglevel (lower numeric value) is printed to the console immediately as it is generated. Messages below the threshold go to the ring buffer only and are visible via dmesg but do not appear on screen.
Read and adjust this threshold via /proc/sys/kernel/printk:
# Read current console loglevel (four fields: current, default, minimum, boot-default) $ cat /proc/sys/kernel/printk 4 4 1 7 # First value: current console loglevel (4 = warn; levels 0-3 print to console) # Second: default message loglevel (messages without explicit level get this) # Third: minimum console loglevel (cannot set console loglevel below this) # Fourth: boot-time default console loglevel # Set console loglevel to 7 (all messages print to console -- useful for debugging) $ sudo dmesg -n 7 # Set console loglevel to 1 (only KERN_EMERG prints to console) $ sudo dmesg -n 1 # Or write directly to the proc file (does not require restarting any daemon) $ echo 3 | sudo tee /proc/sys/kernel/printk
Changing the console loglevel with dmesg -n or via /proc/sys/kernel/printk does not affect what is stored in the ring buffer -- it only controls what is echoed to the active console in real time. All messages are still accessible via dmesg regardless of this setting. The change is volatile: it resets to the compiled-in default on reboot (source: Linux Kernel Documentation, printk-basics).
Filter by Facility
Kernel messages are also tagged with a facility indicating which subsystem produced them. Use -f to filter:
# Kernel messages only (excludes userspace daemon messages) $ sudo dmesg -T -f kern # Combine facility and level filters $ sudo dmesg -T -f kern -l err
Common facilities include kern (the kernel itself), user (userspace programs), daemon (system daemons), and syslog. In practice, kern is the one you'll use most when diagnosing hardware and driver issues.
Searching and Filtering Output
For targeted investigation, pipe dmesg through grep. This is faster than scrolling and essential on systems with verbose kernel output.
# Find USB-related messages $ sudo dmesg -T | grep -i usb # Find disk and storage errors (SATA and NVMe) $ sudo dmesg -T | grep -i -E 'error|fail|I/O error|ata[0-9]|nvme' # Find network interface events $ sudo dmesg -T | grep -i eth0 $ sudo dmesg -T | grep -i 'link is' # Find out of memory (OOM) killer events $ sudo dmesg -T | grep -i 'oom\|killed process' # Find CPU-related messages (thermal, microcode) $ sudo dmesg -T | grep -i 'cpu\|thermal\|microcode' # Find GPU and display driver messages $ sudo dmesg -T | grep -i -E 'drm|gpu|radeon|nvidia|i915'
Add -A 3 or -B 3 to your grep to show a few lines of context around each match. Kernel error messages are frequently preceded by a device identification line that tells you exactly which piece of hardware is involved: sudo dmesg -T | grep -i 'i/o error' -A 3
The kernel ring buffer can expose memory addresses useful for bypassing KASLR (Kernel Address Space Layout Randomization) and other kernel hardening techniques. This is why security-hardened distributions set kernel.dmesg_restrict=1 -- it limits ring buffer access to processes with CAP_SYSLOG and reduces the information available to local attackers. If your system allows unprivileged dmesg access and you are operating in a multi-user or shared environment, consider enabling the restriction (source: Linux Kernel Documentation, kernel.txt). For a broader look at sysctl parameters and kernel hardening, the kernel tuning guide covers the full range of production-relevant settings.
Printk Rate-Limiting and Suppressed Messages
The kernel's printk rate-limiter is one of the least-understood sources of silent data loss in dmesg. When a kernel subsystem emits messages faster than the configured burst threshold, the rate-limiter suppresses the excess and emits a summary line like this:
# General printk rate-limiter summary (RHEL 6/7/8/9 and many other distros) [ 142.883012] __ratelimit: 47 callbacks suppressed # Networking-specific rate-limiter [ 639882.834400] net_ratelimit: 2 callbacks suppressed # Per-function rate-limiter (function name appears before the count) [ 209.441072] ata_sff_interrupt: 10 callbacks suppressed
The number shown is the count of messages that were dropped since the last allowed message from that code path. A count of 47 means you saw 1 message but 47 additional identical messages were silently discarded. The underlying event fired 48 times -- the ring buffer only records one. This matters critically during disk error storms, network flooding events, and OOM pressure cascades: the severity of the event is significantly understated by what dmesg shows.
Two separate rate-limiter configurations control this behavior. The general printk limiter is tuned via:
# Read the current rate-limit window (in seconds, default 5) $ cat /proc/sys/kernel/printk_ratelimit 5 # Read the maximum burst count per window (default 10) $ cat /proc/sys/kernel/printk_ratelimit_burst 10 # Networking code has its own independent rate-limiter $ cat /proc/sys/net/core/message_cost 5 $ cat /proc/sys/net/core/message_burst 10 # Temporarily disable the printk rate-limiter for debugging (set window to 0) # WARNING: on a flooding system this will fill the ring buffer extremely fast $ echo 0 | sudo tee /proc/sys/kernel/printk_ratelimit # Re-enable by restoring the default $ echo 5 | sudo tee /proc/sys/kernel/printk_ratelimit
Disabling printk rate-limiting (printk_ratelimit=0) on a system that is actively generating a flood of kernel messages -- such as a failing storage controller issuing thousands of I/O errors per second -- can fill the ring buffer in seconds, rotating out earlier messages and potentially degrading system responsiveness. Only disable it when you need to capture the exact content of suppressed messages for a specific debugging session, and restore the default immediately after. The rate-limiter exists partly as a denial-of-service protection to prevent malicious or misbehaving userspace from flooding the ring buffer via /dev/kmsg.
Reading Common Kernel Messages
Knowing the commands is only part of it. Here is a guide to what you'll commonly see and what it means.
Boot and Hardware Detection
The first section of a fresh boot covers memory detection, CPU topology, and ACPI table parsing. Lines like BIOS-provided physical RAM map and ACPI: IRQ0 used by override are normal and informational. What you want to watch for are lines tagged with [Firmware Bug] or ACPI BIOS Error -- these indicate firmware issues that may cause instability.
Driver Initialization
After the kernel loads, drivers initialize and report what they found. A successfully loaded driver usually prints something like:
[Fri Mar 20 09:14:02 2026] e1000e 0000:00:1f.6 eth0: renamed from enp0s31f6 [Fri Mar 20 09:14:02 2026] e1000e 0000:00:1f.6 eth0: NIC Link is Up 1000 Mbps Full Duplex
If a driver fails to load or encounters an error, you'll see lines containing failed, error, or can't. These are worth recording before you start troubleshooting. Once the interface is up, identifying which process is using a given port can help correlate driver messages with runtime network behavior.
Storage and Filesystem Errors
Disk errors are among the most important things dmesg surfaces. An ATA or SCSI error looks like this:
[Fri Mar 20 14:23:11 2026] ata1.00: end_request: I/O error, dev sda, sector 4096000 [Fri Mar 20 14:23:11 2026] ata1.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x6 [Fri Mar 20 14:23:11 2026] ata1.00: FAILED: status: { DRDY ERR }
Repeated I/O errors on the same device are a strong signal of impending disk failure. Cross-reference with smartctl -a /dev/sda to check SMART data. A single isolated error after a cable reseat or power event is less concerning, but a stream of them is not something to defer. For a deeper look at how the kernel handles storage requests end to end, the guide to kernel-level I/O events covers the path from syscall through the block layer to DMA.
OOM Killer Events
When the system runs out of memory and the OOM killer activates, dmesg records exactly which process was killed and why. The output is verbose but structured:
[Fri Mar 20 03:41:07 2026] Out of memory: Killed process 8921 (java) total-vm:4194304kB, anon-rss:3801088kB, file-rss:4096kB, shmem-rss:0kB [Fri Mar 20 03:41:07 2026] oom_reaper: reaped process 8921 (java), now anon-rss:0kB
If you find OOM events in dmesg on a production system, the immediate diagnosis is that something consumed more memory than was available. Whether the fix is adding swap, increasing RAM, tuning the JVM heap, or capping a runaway process depends on context -- but dmesg tells you it happened and which process paid the price.
Clearing the Buffer and Buffer Size
On SMP systems, the ring buffer size can be dynamically enlarged at boot based on CPU count. When CONFIG_LOG_CPU_MAX_BUF_SHIFT is set in the kernel configuration and the system has multiple CPUs, the kernel may allocate a per-CPU log buffer that exceeds the base CONFIG_LOG_BUF_SHIFT value. This means the effective ring buffer on a 64-core server may be substantially larger than the value you read from /boot/config-$(uname -r) would suggest. To see the actual runtime size rather than the compile-time default, read /sys/kernel/debug/printk/buffer_size on systems where debugfs is mounted (requires root), or check dmesg --buffer-size output for any truncation warnings:
# Compiled-in base size exponent (2^N bytes) $ grep CONFIG_LOG_BUF_SHIFT /boot/config-$(uname -r) CONFIG_LOG_BUF_SHIFT=17 # Per-CPU expansion threshold (SMP systems -- may result in a larger actual buffer) $ grep CONFIG_LOG_CPU_MAX_BUF_SHIFT /boot/config-$(uname -r) CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 # Override the buffer size at boot -- add to GRUB_CMDLINE_LINUX in /etc/default/grub # then run update-grub (Debian/Ubuntu) or grub2-mkconfig (RHEL/Fedora) # log_buf_len=8M allocates an 8 MB ring buffer CONFIG: GRUB_CMDLINE_LINUX="... log_buf_len=8M"
You can clear the kernel ring buffer with sudo dmesg -C. This is useful before a test run -- plug in a device, reproduce a condition, then read dmesg to see only messages from that event. Clearing requires root and only affects the in-memory buffer, not the journal.
The ring buffer size is set at kernel compile time via the CONFIG_LOG_BUF_SHIFT config option -- a base-2 exponent. A value of 17 means 217 = 128 KB. To see what your running kernel was compiled with, run grep CONFIG_LOG_BUF_SHIFT /boot/config-$(uname -r). Note that the -s / --buffer-size flag in dmesg is not a display command -- it sets the size of the read buffer dmesg uses for its own query, which only matters if you have enlarged the kernel ring buffer beyond the default via the log_buf_len boot parameter (source: Linux Kernel Documentation, kernel.txt).
# Check the compiled-in ring buffer size (CONFIG_LOG_BUF_SHIFT is a base-2 exponent) # e.g. a value of 17 means 2^17 = 128 KB $ grep CONFIG_LOG_BUF_SHIFT /boot/config-$(uname -r) # Clear the buffer (root required) $ sudo dmesg -C # Print and then clear in one step $ sudo dmesg -c
Clearing the ring buffer with dmesg -C is irreversible for any messages not already captured by journald or a syslog daemon. On a system where journald persistence is configured, kernel messages are already saved to disk -- so clearing is safe. On a system logging only to the ring buffer, you lose those messages permanently.
dmesg vs. journalctl -k
On systemd-based systems, journalctl -k is often a better tool for historical kernel message investigation because journald persists messages across reboots. The two commands overlap significantly but differ in important ways.
dmesg reads directly from the in-memory ring buffer. It is always available, even on minimal systems without systemd, and is the correct tool for live diagnostics and situations where you need the most recent kernel output instantly. It also works over SSH before systemd-journald has fully started -- which matters during early-boot troubleshooting.
journalctl -k queries the journal database, which survives reboots (if persistence is configured) and supports richer filtering syntax. Use journalctl -k -b -1 to see kernel messages from the previous boot -- something dmesg cannot do on its own, since the ring buffer is cleared at shutdown. For investigating a crash that required a hard reboot, journalctl -k -b -1 is the right starting point, assuming persistent journald logging was enabled before the event.
Use dmesg for what is happening now. Use journalctl -k for what happened last night.
One practical difference: journalctl -k supports structured field filtering via -k _TRANSPORT=kernel and rich time expressions like journalctl -k --since "2026-04-08 22:00" --until "2026-04-08 23:00". For a production system with persistent journald configured, those filters give you surgical precision. But for anything live -- a USB disconnect, a module load, an OOM event happening right now -- dmesg -Tw gets you there faster (source: systemd journalctl man page, freedesktop.org).
How to Use dmesg for Common Diagnostic Tasks
Step 1: Run dmesg with human-readable timestamps
Run sudo dmesg -T to print the full kernel ring buffer with human-readable wall-clock timestamps instead of the default seconds-since-boot format. Pipe through less for comfortable scrolling: sudo dmesg -T | less
Step 2: Filter kernel messages by log level
Use sudo dmesg -l err,warn to display only error and warning messages. Combine with -T for readable timestamps. Use sudo dmesg -l crit,alert,emerg to surface only the highest-severity kernel messages.
Step 3: Search dmesg output for a specific device or driver
Pipe dmesg through grep to find messages about a specific device or subsystem. For example: sudo dmesg -T | grep -i usb to inspect USB-related events, or sudo dmesg -T | grep -i 'error\|fail' to catch all error-related lines in one pass. For NVMe storage, use sudo dmesg -T | grep -i nvme.
Step 4: Check the ring buffer size
Run grep CONFIG_LOG_BUF_SHIFT /boot/config-$(uname -r) to find the compiled-in ring buffer size exponent. A value of 17 means 217 = 128 KB. If early boot messages are missing on a verbose system, you may need to increase the buffer at boot via log_buf_len=8M in your kernel parameters.
Step 5: Use --since for time-bounded investigation
On util-linux 2.36 and later, sudo dmesg -T --since '1 hour ago' limits output to a specific time window. This is faster and more precise than grepping timestamps manually, especially when correlating a known incident time with kernel activity.
Frequently Asked Questions
What does dmesg stand for?
dmesg stands for "diagnostic message" (sometimes cited as "display message"). It prints the kernel ring buffer, which holds messages written by the Linux kernel during boot and while the system is running -- covering hardware detection, driver initialization, kernel errors, and system events.
Why do dmesg timestamps show seconds instead of a real date?
By default, dmesg shows timestamps as seconds elapsed since boot, not wall-clock time. To see human-readable dates and times, run dmesg -T (or dmesg --ctime). However, -T can be significantly inaccurate on systems that have been suspended and resumed. The kernel monotonic clock pauses during suspend while the wall clock keeps running; on a laptop with weeks of uptime and regular sleep cycles, the accumulated offset can be hours or days -- messages may appear timestamped in the future. -T is reliable only for messages generated since the last resume. For accurate wall-clock timestamps on any system that suspends, use journalctl -k, which records wall time at message ingestion. Raw monotonic output (the default, without -T) remains internally consistent and is preferable for scripted log analysis.
Does dmesg require root to run?
It depends on the kernel.dmesg_restrict sysctl setting. The upstream Linux kernel default is 0 (no restriction), but many distributions -- including Ubuntu, Debian, and Fedora -- ship with it set to 1 via their hardening configurations. When dmesg_restrict is 1, reading the ring buffer requires the CAP_SYSLOG capability. In practice, sudo dmesg is the safe default. The feature has been present since kernel 2.6.37 (source: Linux Kernel Documentation, kernel.txt). To check the current value on your system, run cat /proc/sys/kernel/dmesg_restrict.
How do I check the current kernel ring buffer size?
The ring buffer size is defined at kernel compile time by CONFIG_LOG_BUF_SHIFT, a base-2 exponent. Read it with grep CONFIG_LOG_BUF_SHIFT /boot/config-$(uname -r). If that file is not present, try /proc/config.gz (if enabled). A value of 17 means 128 KB; a value of 21 means 2 MB. You can override the size at boot with the log_buf_len kernel parameter. Note that dmesg --buffer-size does not display the ring buffer size -- it controls the internal read buffer dmesg allocates to query the kernel, which is relevant only when the ring buffer has been enlarged beyond the defaults.
What does 'callbacks suppressed' mean in dmesg output?
When the kernel's printk rate-limiter activates, it silently drops messages that exceed the configured burst threshold and then emits a summary like __ratelimit: N callbacks suppressed or net_ratelimit: N callbacks suppressed. The threshold is controlled by two proc files: /proc/sys/kernel/printk_ratelimit (minimum seconds between message groups, default 5) and /proc/sys/kernel/printk_ratelimit_burst (maximum messages per interval, default 10). Networking code has its own independent limiter at /proc/sys/net/core/message_cost and /proc/sys/net/core/message_burst. Seeing a count of 47 means the underlying event fired 48 times -- the ring buffer records only one. The suppression count is the precise measure of how much data is missing.
What is the difference between /dev/kmsg and /proc/kmsg?
/dev/kmsg (since kernel 3.5.0) supports multiple concurrent readers, provides structured per-record access including sequence numbers, and is non-destructive -- reading it does not advance any shared pointer. /proc/kmsg is a destructive stream: reading it advances the kernel's internal read pointer and consumes entries. Only one process can read /proc/kmsg at a time. If a syslog daemon is already reading it, a second reader will block or receive incomplete output. dmesg has used /dev/kmsg by default since kernel 3.5.0 and falls back to the syslog(2) syscall with the -S flag. A gap in sequence numbers between two consecutive /dev/kmsg records is a precise indicator that messages were overwritten by ring buffer rotation -- not merely filtered.
What is the difference between dmesg -w and dmesg -W?
dmesg -w (or --follow) prints the full existing ring buffer and then waits for new messages, behaving like tail -f. dmesg -W (or --follow-new), available in util-linux 2.28 and later, skips the existing buffer entirely and only prints messages that arrive after the command is invoked. Use -W when you want a clean watch for a specific hardware event -- plug in a USB device, trigger a kernel module load -- without first scrolling through accumulated output.