Skip to content
SumGuy's Ramblings
Go back

Linux Suspend and Hibernate: Teaching Your Machine to Take a Nap Without Dying

Sleep Is a Spectrum (And Linux Takes That Literally)

On Windows you hit sleep and stuff works. On Linux, you might suspend successfully for a week and then one day wake up to a hung system, a blank screen, or a kernel panic that takes your session with it. It’s not Linux’s fault specifically — the firmware, hardware, and drivers are all conspiring against you — but you need to understand what’s happening to fix it.

There are multiple sleep states. They trade power savings for complexity and resume reliability. Here’s the breakdown:

The Sleep States (S1 through S4)

The ACPI spec defines sleep states S1 through S5 (S5 is powered off). The useful ones:

S1 — CPU Stop Grant: CPU stops executing instructions, RAM stays powered. Very fast resume, almost no power savings. Almost nobody uses this.

S2 — Similar to S1: CPU powered off. Rare. Not really a thing on modern hardware.

S3 — Suspend to RAM (STR): The one you call “sleep.” CPU and most devices powered off. RAM stays powered to retain state. Typically uses 1-5 watts. Resume in 1-3 seconds. This is what systemctl suspend does.

S4 — Hibernate (Suspend to Disk): Everything written to swap/disk, then powered off completely. Uses 0 watts. Resume in 10-30 seconds (basically a specialized boot). This is what systemctl hibernate does.

Hybrid Sleep: Saves state to disk (like hibernate) but also stays in S3 (like suspend). If power is lost, it can resume from disk. Best of both worlds, slightly slower to enter than pure suspend.

# What sleep states does your hardware support?
cat /sys/power/state
# Typical output: freeze mem disk

# Check supported hibernation modes
cat /sys/power/disk
# Typical output: platform shutdown reboot suspend [platform]

Suspend to RAM: Usually Just Works

# Suspend immediately
systemctl suspend

# Or the old way
echo mem > /sys/power/state

Suspend usually works on modern hardware. When it doesn’t, the problems are:

Debug it:

# Check what happened during last suspend/resume cycle
journalctl -b -1 -u systemd-sleep
journalctl -b -1 | grep -i "suspend\|resume\|wake"

# See what's blocking suspend
cat /sys/power/wakeup_count
cat /proc/acpi/wakeup

Hibernate: Requires More Setup

Hibernate is trickier because it requires a properly configured swap space and the initramfs needs to know where to find it.

Step 1: Make Sure You Have Enough Swap

For hibernate, you need swap space at least as large as your RAM. More is better because your RAM might not be 100% used.

# Check current swap
swapon --show
free -h

# If you need more swap — create a swapfile
sudo fallocate -l 16G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# Make it permanent
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

For a dedicated swap partition, the partition already exists in most installs — just verify it’s large enough.

Step 2: Find the Resume Device

You need to tell the kernel where to find the saved hibernate image on boot.

# Find your swap partition or file's UUID
sudo blkid | grep swap
# OR for a swapfile:
stat /swapfile
# Note the device it's on

# For a swapfile, get the offset
sudo filefrag -v /swapfile | head -5
# The first extent's physical_offset is what you need

Step 3: Configure GRUB for Resume

Edit your GRUB config:

sudo nano /etc/default/grub

For a swap partition:

GRUB_CMDLINE_LINUX="resume=UUID=your-swap-uuid-here"

For a swapfile (replace with your actual device UUID and offset):

GRUB_CMDLINE_LINUX="resume=UUID=your-root-device-uuid resume_offset=12345678"

Then update GRUB:

# Debian/Ubuntu
sudo update-grub

# RHEL/Fedora
sudo grub2-mkconfig -o /boot/grub2/grub.cfg

Step 4: Update the Initramfs

The initramfs needs to include the resume hook so it can restore the hibernate image on boot:

# Ubuntu/Debian — edit initramfs config
cat /etc/initramfs-tools/conf.d/resume
# Should contain: RESUME=UUID=your-swap-uuid

# If it doesn't exist or is wrong, create/edit it:
echo "RESUME=UUID=$(findmnt -no UUID /swapfile 2>/dev/null || blkid -s UUID -o value /dev/sdX)" \
    | sudo tee /etc/initramfs-tools/conf.d/resume

# Rebuild initramfs
sudo update-initramfs -u -k all

# Test hibernate
systemctl hibernate

If it works, your system powers off and comes back with your session intact. If it doesn’t, check journalctl -b -1 for clues.

UEFI Secure Boot Complications

Hibernate can fail with Secure Boot if the hibernate image is considered untrusted. The typical symptom: system resumes to a fresh session instead of your saved state, or refuses to load the hibernate image entirely.

The kernel checks that the hibernate image was created by a trusted kernel. If you’re using DKMS modules (like NVIDIA drivers or VirtualBox) and they’re not signed, Secure Boot can interfere.

Options:

  1. Disable Secure Boot in UEFI settings (easiest for home lab)
  2. Sign your kernel modules properly (the Right Way)
  3. Use lockdown=integrity kernel parameter and accept the limitations
# Check if Secure Boot is enabled
mokutil --sb-state

# Check if lockdown is active
cat /sys/kernel/security/lockdown

Hybrid Sleep: The Best Compromise

For laptops and machines where power cuts are possible, hybrid sleep is often the best option:

# Enable hybrid sleep as the default sleep mode
sudo nano /etc/systemd/sleep.conf
[Sleep]
SuspendMode=suspend
HibernateMode=platform shutdown
HybridSleepMode=suspend platform shutdown
HybridSleepDelay=120min
SuspendState=mem
HibernateState=disk
HybridSleepState=disk
# Test hybrid sleep
systemctl hybrid-sleep

The HybridSleepDelay option in newer systemd means: suspend normally, but if the system is still asleep after that duration, automatically hibernate. Brilliant for laptops — fast wakes for short naps, full hibernation for overnight.

Laptop Lid Close Behavior

This drives everyone insane at least once. Control it in /etc/systemd/logind.conf:

[Login]
HandleLidSwitch=suspend          # What to do when lid closes
HandleLidSwitchExternalPower=suspend  # When plugged in
HandleLidSwitchDocked=ignore     # When docked (connected to external display)
IdleAction=suspend               # What to do after idle timeout
IdleActionSec=30min
sudo systemctl restart systemd-logind

Options for HandleLidSwitch: suspend, hibernate, hybrid-sleep, suspend-then-hibernate, poweroff, ignore.

Wake-on-LAN

Wake-on-LAN (WoL) lets you remotely wake a sleeping machine by sending a “magic packet” to its MAC address. Useful for home labs where you want a server to suspend when idle but wake on demand.

# Check if your NIC supports WoL
sudo ethtool eth0 | grep -i wake

# Enable WoL
sudo ethtool -s eth0 wol g  # g = magic packet

# Make it persistent with a systemd service
# /etc/systemd/system/wol.service
[Unit]
Description=Enable Wake-on-LAN
After=network.target

[Service]
Type=oneshot
ExecStart=/sbin/ethtool -s eth0 wol g
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
sudo systemctl enable --now wol.service

# Send the magic packet from another machine
# Install wakeonlan: sudo apt install wakeonlan
wakeonlan AA:BB:CC:DD:EE:FF
# Or with etherwake
sudo etherwake -i eth0 AA:BB:CC:DD:EE:FF

For WoL to work through suspension, you also need to enable it in the UEFI/BIOS settings under “Power Management” or similar.

Troubleshooting Common Failures

System suspends but wakes up immediately: Something is triggering a wakeup. Check:

cat /proc/acpi/wakeup
# Disable a wakeup source (e.g., USB)
echo USB3 | sudo tee /proc/acpi/wakeup

Blank screen after resume: Usually a GPU driver issue. Try:

# For NVIDIA
sudo systemctl enable nvidia-suspend.service
sudo systemctl enable nvidia-hibernate.service
sudo systemctl enable nvidia-resume.service

Hibernate fails with “not enough swap”: Your swap is too small. Add more swap space.

Resume from hibernate boots to login screen instead of session: Usually a display manager issue, not a hibernate failure. Your session is restored at the kernel level, but the display manager intercepts before showing it. Check if your DM has a “resume session” option.

System won’t hibernate, returns to running state immediately: Check systemd-inhibit --list — something is holding an inhibitor lock:

systemd-inhibit --list
# Kill the offending process or wait for it to finish

Getting suspend and hibernate working properly takes some tuning, but once it’s dialed in, you stop thinking about it entirely. The payoff — especially for laptops — is real: faster wake times than a full boot, battery preservation, and sessions that survive overnight without running your fans all night.

Your laptop deserves to sleep. Let it.


Share this post on:

Previous Post
Appwrite: Your Own Firebase, Minus the Google Surveillance Subscription
Next Post
Sysctl Tuning: The Linux Kernel Knobs That Actually Matter