What you will learn in this tutorial
You have compiled your first custom Linux kernel. Now what? Before you can actually run it,
you need to tell your system which kernel to boot. That is the job of the bootloader —
in almost all Linux systems today, that is GRUB2 (GNU GRand Unified Bootloader version 2).
In this tutorial you will understand exactly what GRUB2 does, how to control the boot timeout,
how to select which kernel boots by default, and how to safely boot your freshly compiled kernel
without losing the ability to fall back to your original one.
GRUB timeout settings
Default kernel selection
/etc/default/grub
update-grub command
Booting custom kernel
Kernel fallback strategy
Linux 6.x boot process
What exactly is GRUB2?
When you press the power button, your computer’s firmware (BIOS or UEFI) does some hardware checks
and then hands over control to the bootloader. On most Linux systems, that bootloader is GRUB2.
GRUB2’s main job is simple: present you a menu of kernels and let you pick one. Once you pick
(or the timeout expires and it picks automatically), GRUB2 loads that kernel image into memory,
passes some parameters to it, and steps aside. The kernel takes over from there.
|
1. Power ON
Hardware initialises
|
→ |
2. BIOS / UEFI
POST, finds boot device
|
→ |
3. GRUB2
Shows kernel menu, loads kernel
|
→ |
4. Linux Kernel
Boots, mounts rootfs, runs init
|
GRUB2 reads its configuration from /boot/grub/grub.cfg. But here is the important rule:
you must never edit that file directly. It is auto-generated. All your changes
go into /etc/default/grub, and after saving, you run sudo update-grub
to regenerate grub.cfg from your settings.
|
You edit this:
/etc/default/grub
Simple key=value settings. Safe to edit.
|
+
/etc/grub.d/ scripts
|
sudo
update-grub |
→ |
Auto-generated (do NOT touch):
/boot/grub/grub.cfg
Complex GRUB script. Regenerated every time.
|
Controlling the GRUB boot menu timeout
When GRUB2 shows its menu, it waits for a few seconds before automatically booting the default
kernel. This wait time is set by the GRUB_TIMEOUT directive inside
/etc/default/grub.
By default in Ubuntu and many Debian-based distros, the timeout is set to a short duration or even
hidden. When you are doing kernel development, you want to see the menu and be able to pick your
newly compiled kernel. So you need to make the menu visible and give yourself enough time to choose.
Step-by-step: Making the GRUB menu visible and setting the timeout
Open the GRUB defaults file with superuser privileges:
sudo nano /etc/default/grub
GRUB_TIMEOUT line and set it to how many seconds you want the menu to wait.A value of 5 or 10 seconds is comfortable for development:
GRUB_TIMEOUT=5
The special values 0 (boot immediately, skip menu) and -1 (wait forever, never auto-boot) also work.
GRUB_TIMEOUT_STYLE. If it says hidden, change it to menu:
GRUB_TIMEOUT_STYLE=menu
If you see a line like GRUB_HIDDEN_TIMEOUT=1, comment it out by putting a # in front:
#GRUB_HIDDEN_TIMEOUT=1
Save the file and apply your changes:
sudo update-grub
This command scans your /boot directory, finds all installed kernels, and regenerates
the grub.cfg file. It also typically refreshes the initramfs images.
In newer Ubuntu versions the old
GRUB_HIDDEN_TIMEOUT directive is no longer used.The correct setting to control menu visibility is
GRUB_TIMEOUT_STYLE.Set it to
menu so the boot menu always appears. The deprecatedGRUB_HIDDEN_TIMEOUT_QUIET setting from older tutorials can be safely ignoredon Linux 6.x systems.
| Setting value | What happens | When to use |
|---|---|---|
GRUB_TIMEOUT=0 |
Boots immediately, no menu shown | Production systems, not for development |
GRUB_TIMEOUT=5 |
Menu shows for 5 seconds then auto-boots default | Good for kernel development (recommended) |
GRUB_TIMEOUT=10 |
Menu shows for 10 seconds | If you need more time to read and decide |
GRUB_TIMEOUT=-1 |
Menu waits indefinitely, never auto-boots | Debugging sessions where you always want to choose |
Choosing which kernel boots by default
GRUB2 can have multiple kernels listed in its menu. Think about it — when you install a new kernel,
the old one does not disappear. Both are available. The GRUB_DEFAULT setting in
/etc/default/grub decides which one boots automatically when the timeout runs out.
Method 1 — Boot by position (simplest)
By default, GRUB_DEFAULT=0 means “boot the first entry in the menu”, which is always
the most recently installed kernel. This is usually what you want for development — install your
new kernel and it automatically becomes the first entry.
# Boot the first (newest) kernel — this is the default behaviour
GRUB_DEFAULT=0
Method 2 — Boot by exact name (precise control)
If you want to lock in a specific kernel regardless of what else gets installed, you can use its
full name. First, check what kernels are available on your system:
# List all kernel entries that GRUB knows about
grep -E "^menuentry|submenu" /boot/grub/grub.cfg | cut -d "'" -f2
You will see output similar to this (the exact kernel versions will differ on your machine):
Ubuntu
Advanced options for Ubuntu
Ubuntu, with Linux 6.8.0-60-generic
Ubuntu, with Linux 6.8.0-60-generic (recovery mode)
Ubuntu, with Linux 6.8.0-mykernel
Ubuntu, with Linux 6.8.0-mykernel (recovery mode)
If the kernel you want is inside the “Advanced options” submenu (which is common in modern Ubuntu),
you must include the submenu name using a > separator:
GRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu, with Linux 6.8.0-mykernel"
GRUB_DEFAULT,the setting does not update automatically when a new kernel is installed.
You have to come back and change it manually, then run
sudo update-grub again.For day-to-day kernel development, using
GRUB_DEFAULT=0 (always boot newest) orthe “saved” method below is usually more practical.
Method 3 — Remember the last boot choice (most flexible)
There is a handy option that makes GRUB2 remember whatever you booted last time and use it again
next time. This is great during development — you can pick your custom kernel once and it keeps
booting it:
GRUB_DEFAULT=saved
GRUB_SAVEDEFAULT=true
With this setup, whatever you select from the GRUB menu on one boot becomes the automatic choice
for all future boots — until you change it again from the menu.
| Method | Setting | Pros | Cons |
|---|---|---|---|
| By position | GRUB_DEFAULT=0 |
Simple, no maintenance | Always picks newest — may not be what you want |
| By name | GRUB_DEFAULT="submenu>entry" |
Very precise control | Must update manually after every kernel change |
| By last choice | GRUB_DEFAULT=saved |
Remembers your pick automatically | Requires GRUB_SAVEDEFAULT=true too |
Applying your GRUB changes
Every time you edit /etc/default/grub, you must run this command to regenerate the
actual GRUB configuration:
sudo update-grub
On Fedora and RHEL-based systems, the equivalent command is:
# Fedora / RHEL / Rocky Linux
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
After running update-grub, you are ready to reboot:
sudo reboot
What the GRUB menu looks like at boot time
When your machine restarts, if the GRUB menu is configured to show, you will see a simple text menu.
Here is how to understand what you are seeing:
A few things to notice here:
- Modern Ubuntu (20.04 and later) shows the latest kernel directly on the main menu. Older kernels are inside the “Advanced options” submenu.
- Every kernel gets a matching recovery mode entry. This boots the kernel with a minimal set of services and gives you a root shell — useful when a new kernel breaks something.
- The default entry (the one GRUB will auto-boot) is marked with an asterisk
*or highlighted.
Use the ↑ ↓ arrow keys to move between entries.
Press Enter to boot the highlighted entry.
Press e to temporarily edit the boot command (useful for debugging).
Press c to get a GRUB command-line.
Press any key (except Enter) to stop the countdown timer.
Safety strategy — never delete your original kernel
When you are doing kernel development, you will compile and install multiple kernels.
A very important rule: never delete your original distribution kernel.
Think about what happens if your custom kernel has a bug and fails to boot — perhaps a driver
crashes early, or the filesystem support is not compiled in. You need a working kernel to fall
back to so you can fix the issue and try again. The distro kernel is your safety net.
|
✅ Recommended approach
|
❌ Dangerous approach
|
no recovery option, you can boot a live Linux system from a USB drive. From there you can mount
your root filesystem, chroot into it, and reinstall or fix a kernel. This is advanced recovery
but knowing it exists reduces the fear of experimentation.
A complete working /etc/default/grub for kernel development
Here is a clean example of what a good /etc/default/grub looks like when you are
actively doing kernel development on Ubuntu 22.04 / 24.04:
# /etc/default/grub — Kernel development setup
# Boot the most recently installed kernel by default
GRUB_DEFAULT=0
# Always show the GRUB menu (do not hide it)
GRUB_TIMEOUT_STYLE=menu
# Wait 5 seconds for user input before auto-booting
GRUB_TIMEOUT=5
# Distro name for GRUB display
GRUB_DISTRIBUTOR=`lsb_release -i -s 2>/dev/null || echo Debian`
# Kernel boot parameters (remove 'quiet splash' to see boot messages)
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX=""
After saving this file, always run:
sudo update-grub
GRUB_CMDLINE_LINUX_DEFAULTfrom
"quiet splash" to just "" (empty string). This removes the splashscreen and shows all kernel boot messages on the console, making it much easier to spot where
the boot process fails if something goes wrong.
Interview Questions — GRUB2 and Kernel Boot
distributions. After the system firmware (BIOS or UEFI) completes its hardware checks, it
hands control to GRUB2. GRUB2 then reads its configuration, presents a menu of available
kernels, loads the selected kernel image and its initramfs into memory, and passes control
to the kernel. GRUB2 itself is no longer involved once the kernel starts running.
/boot/grub/grub.cfg is an auto-generated file. Running sudo update-grubcompletely overwrites it. Any manual changes you make will be lost the next time update-grub
runs — for example when you install a new kernel. The correct approach is to edit
/etc/default/grub for user-level settings, then let update-grubregenerate
grub.cfg from that and from the scripts in /etc/grub.d/.GRUB_TIMEOUT=0, GRUB boots the default kernel immediately without showingany menu. This is typical for production servers where you never want user interaction at boot.
GRUB_TIMEOUT=-1 makes GRUB wait indefinitely — the system will never auto-bootand will sit at the GRUB menu until someone presses Enter. This is useful in debugging scenarios
where you always want to manually confirm which kernel to boot.
kernels are inside the “Advanced options for Ubuntu” submenu. To set one of those as the default,
you use the submenu name and the entry name separated by a
> character inGRUB_DEFAULT. For example:GRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu, with Linux 6.8.0-mykernel"After editing, run sudo update-grub for the change to take effect.
GRUB_DEFAULT=saved tells GRUB to look up a previouslysaved entry and boot that, rather than using a hardcoded position or name.
GRUB_SAVEDEFAULT=true tells GRUB to automatically save whatever the user picksfrom the menu as the new default for next time. You need both set together for the
“remember last choice” behaviour to work correctly.
or any number of bugs introduced during development. If you deleted the original distro kernel
and your custom kernel fails, you are left with an unbootable system. Keeping the original
kernel gives you a reliable fallback — you can select it from the GRUB menu, boot into a working
system, diagnose what went wrong, fix the issue, and try again. It is a basic safety practice
for kernel development.
sudo update-grub on Ubuntu/Debian systems (equivalent tosudo grub-mkconfig -o /boot/grub/grub.cfg). You must run it any time you change/etc/default/grub, install a new kernel, or modify anything in /etc/grub.d/.Without running it, your changes have no effect because
/boot/grub/grub.cfg — thefile GRUB actually reads at boot — has not been updated yet.
e in the GRUB menu opens a temporary editor that lets you modify thekernel boot parameters for that single boot. Changes made this way are not saved permanently —
they only apply to the current boot. This is extremely useful for kernel developers because
you can add debugging parameters (like
debug, earlyprintk,ignore_loglevel), change the root device, or disable specific subsystems tonarrow down a boot failure — all without permanently modifying your GRUB configuration.
Continue Learning — Free Linux Kernel Development Course
EmbeddedPathashala is a completely free educational platform covering Linux kernel programming,
embedded systems, Bluetooth/BLE development, and Linux device drivers. All content is written
by working embedded engineers for students and professionals.
