Every time you power on a Linux machine, a fast, carefully choreographed sequence of events happens in just a few seconds: hardware initializes, the kernel loads, and finally a fully interactive system appears. Understanding this boot process — especially the role of the init process and (historically) run levels — is essential for troubleshooting boot failures, customizing startup behavior, and simply understanding what’s happening “under the hood” of a Linux system.
The Big Picture: Boot Stages
flowchart TD
A[Power On / BIOS-UEFI POST] --> B[Bootloader - GRUB]
B --> C[Kernel Loads into Memory]
C --> D[Kernel Initializes Hardware and Mounts Root Filesystem]
D --> E[Kernel Starts init - PID 1]
E --> F[init/systemd Starts Services in Order]
F --> G[System Reaches Target Run Level]
G --> H[Login Prompt / Desktop Ready]Let’s walk through each stage in detail.
Stage 1: Firmware (BIOS/UEFI) and POST
When you press the power button, the motherboard’s firmware — either legacy BIOS or modern UEFI — runs a Power-On Self-Test (POST) to check that essential hardware (CPU, RAM, storage controllers) is working. It then locates a bootable device according to the configured boot order.
Stage 2: The Bootloader
The firmware hands control to a bootloader, almost always GRUB (GRand Unified Bootloader) on Linux systems. GRUB’s job is to:
- Present a boot menu (if configured, e.g., to choose between kernel versions or operating systems)
- Load the selected Linux kernel into memory
- Load an initial RAM disk (initramfs) — a small temporary filesystem containing drivers needed to mount the real root filesystem
- Pass control to the kernel
You can view your current GRUB configuration:
sudo cat /boot/grub/grub.cfg | head -40Stage 3: The Kernel Takes Over
Once loaded, the Linux kernel:
- Initializes the CPU, memory management, and detected hardware drivers
- Mounts the initramfs as a temporary root filesystem
- Uses drivers within the initramfs to locate and mount the real root filesystem (e.g., your
/partition on disk) - Switches from the temporary initramfs root to the real root filesystem (a process called
pivot_rootorswitch_root) - Starts the very first user-space process: PID 1, traditionally called
init
Stage 4: PID 1 — The init Process
PID 1 is special: it’s the ancestor of every other process on the system, and it’s responsible for starting (and eventually reaping) all other processes. On modern Linux distributions, PID 1 is systemd. On older systems, it was SysVinit’s /sbin/init.
ps -p 1 -o comm=On a modern Ubuntu or CentOS system, this will print systemd.
Run Levels: The Legacy Model (SysVinit)
Before systemd became standard, Linux systems used SysVinit, which organized system states into numbered run levels. Each run level represented a different operating mode:
| Run Level | Meaning |
|---|---|
| 0 | Halt (shuts down the system) |
| 1 | Single-user mode (maintenance/rescue mode, no networking) |
| 2 | Multi-user mode, no networking (Debian-specific meaning) |
| 3 | Full multi-user mode, text-only (no GUI) |
| 4 | Undefined/custom (rarely used) |
| 5 | Full multi-user mode with GUI (X11 display manager) |
| 6 | Reboot |
On SysVinit systems, the default run level was set in /etc/inittab:
id:5:initdefault:This meant the system would boot directly into run level 5 (graphical mode).
You could check and change run levels manually:
runlevel # show current run level
sudo init 3 # switch to run level 3systemd Targets: The Modern Replacement
Modern systemd-based distributions replaced numbered run levels with named targets, which are more flexible and can represent arbitrary combinations of services, not just a single number.
flowchart LR
A[systemd Boot] --> B[sysinit.target]
B --> C[basic.target]
C --> D{Graphical or Text?}
D -->|Text mode| E[multi-user.target]
D -->|GUI mode| F[graphical.target]
F --> E
Mapping Old Run Levels to New Targets
| SysVinit Run Level | systemd Target |
|---|---|
| 0 | poweroff.target |
| 1 | rescue.target |
| 2, 3, 4 | multi-user.target |
| 5 | graphical.target |
| 6 | reboot.target |
Checking the Current Target
systemctl get-defaultChanging the Default Target Permanently
sudo systemctl set-default multi-user.targetThis is the modern equivalent of editing /etc/inittab to change initdefault.
Switching Targets Temporarily (Without Rebooting)
sudo systemctl isolate multi-user.targetThis is equivalent to the old init 3 command, immediately switching the running system to text-mode (stopping the graphical display manager, for example).
Booting Into Rescue/Emergency Mode
sudo systemctl rescueOr, to fix a system that won’t boot normally, you can add systemd.unit=rescue.target as a kernel boot parameter at the GRUB menu.
A Practical Example: Diagnosing a Slow Boot
systemd provides built-in tools to analyze exactly how long each part of the boot process took:
systemd-analyzeExample output:
Startup finished in 3.912s (kernel) + 8.221s (userspace) = 12.133sTo see which specific services took the longest:
systemd-analyze blameTo visualize the boot process as a chart:
systemd-analyze plot > boot-chart.svgReal-World Use Case: Emergency Recovery
Imagine a server won’t boot to a normal login prompt after a bad configuration change. At the GRUB menu:
- Highlight the kernel entry and press
eto edit boot parameters - Find the line starting with
linuxand append:systemd.unit=rescue.target - Press
Ctrl+XorF10to boot with this temporary change - The system boots into a minimal single-user rescue shell where you can fix the broken configuration
- Reboot normally afterward
This is functionally identical to the old trick of appending single or 1 at the GRUB kernel line on SysVinit systems.
Comparison: SysVinit vs. systemd Boot Model
| Aspect | SysVinit | systemd |
|---|---|---|
| PID 1 program | /sbin/init | /usr/lib/systemd/systemd |
| Startup style | Sequential, script-based | Parallel, dependency-based |
| System states | Numbered run levels (0–6) | Named targets |
| Config file for default state | /etc/inittab | systemctl set-default |
| Boot diagnostics | Manual log inspection | systemd-analyze built-in tooling |
| Speed | Slower (sequential) | Faster (parallel where possible) |
Best Practices
- Learn
systemd-analyze blame— it’s the fastest way to find what’s slowing down your boot time. - Never disable critical targets (like
basic.target) without understanding dependencies — this can leave a system unbootable. - Keep a rescue/live USB handy for any production server, in case you need to boot outside the normal chain to fix a broken configuration.
- Document your default target for any server, especially ones intentionally set to
multi-user.target(headless, no GUI) versusgraphical.target. - Test kernel updates in a non-production environment first, since boot-stage issues are among the hardest to debug remotely.
Troubleshooting
Problem: System hangs at boot with no error message
Try adding systemd.log_level=debug to the kernel boot parameters at GRUB to get more verbose boot logging.
Problem: System boots into emergency mode unexpectedly
Check for a filesystem mount failure, often from a bad /etc/fstab entry:
journalctl -xbProblem: GUI doesn’t start, drops to text login
Check the default target and the display manager service:
systemctl get-default
systemctl status gdm # or lightdm, sddm, etc.Problem: Need to boot without a broken service starting
Temporarily mask the problematic service from the GRUB rescue shell or a live environment:
sudo systemctl mask problem-serviceProblem: systemd-analyze shows one service taking excessively long
Investigate that service’s own logs and dependencies:
journalctl -u slow-service.service --no-pagerConclusion
The Linux boot process is a layered handoff: firmware to bootloader, bootloader to kernel, kernel to PID 1, and PID 1 to the rest of userspace. While the legacy SysVinit run-level model (0–6) is still worth understanding for older systems and general Linux literacy, systemd‘s target-based model has become the modern standard, offering faster, parallelized startup and much better built-in diagnostics through tools like systemd-analyze. Mastering both models means you can confidently boot, diagnose, and recover any Linux system you encounter.