GRUB (GRand Unified Bootloader) is the first thing that runs after the firmware. It shows the boot menu, loads the kernel and passes it boot parameters. You rarely touch it, but when you need to boot an older kernel, add a kernel parameter or repair a server that doesn’t boot, knowing GRUB is essential.
The files
/etc/default/grub— the file you edit: timeout, default entry, kernel parameters./etc/grub.d/— scripts that generate menu entries./boot/grub/grub.cfg(Debian/Ubuntu) or/boot/grub2/grub.cfg(RHEL family) — the generated config. Don’t edit it by hand, because it’s overwritten on every kernel update.
After editing /etc/default/grub, regenerate the config:
sudo update-grub # Debian/Ubuntu
sudo grub2-mkconfig -o /boot/grub2/grub.cfg # RHEL family (BIOS and modern UEFI)
Common settings
GRUB_DEFAULT=0
GRUB_TIMEOUT=5
GRUB_TIMEOUT_STYLE=menu
GRUB_CMDLINE_LINUX_DEFAULT="quiet"
GRUB_CMDLINE_LINUX=""
- GRUB_TIMEOUT — seconds the menu waits. Cloud images often set 0 or a hidden menu, which makes it hard to choose another kernel from the console. Set it to 5 with
TIMEOUT_STYLE=menuif you want a chance to intervene. - GRUB_CMDLINE_LINUX — kernel parameters for every boot entry.
- GRUB_CMDLINE_LINUX_DEFAULT — parameters for normal boots only (Debian/Ubuntu), not for recovery entries.
Cloud images may override these in /etc/default/grub.d/*.cfg. Check there if your changes don’t take effect.
Boot an older kernel by default
List the menu entries:
grep -E "menuentry '|submenu '" /boot/grub/grub.cfg | cut -d"'" -f2
Set the default to a specific entry (submenu > entry):
# /etc/default/grub
GRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu, with Linux 6.8.0-85-generic"
Then run sudo update-grub.
Or remember whatever was booted last:
GRUB_DEFAULT=saved
GRUB_SAVEDEFAULT=true
Boot a different entry once, for the next boot only:
sudo grub-reboot "Advanced options for Ubuntu>Ubuntu, with Linux 6.8.0-85-generic"
sudo reboot
On RHEL-family systems, grubby manages kernels directly:
sudo grubby --info=ALL | grep -E '^kernel|^index'
sudo grubby --set-default /boot/vmlinuz-5.14.0-427.el9.x86_64
sudo grubby --default-kernel
Add kernel parameters
Example: disable a feature or enable cgroup options.
# /etc/default/grub
GRUB_CMDLINE_LINUX="… existing … systemd.unified_cgroup_hierarchy=1"
Run sudo update-grub, reboot, then check cat /proc/cmdline.
RHEL family:
sudo grubby --update-kernel=ALL --args="systemd.unified_cgroup_hierarchy=1"
sudo grubby --update-kernel=ALL --remove-args="quiet"
Common parameters:
| Parameter | Use |
|---|---|
console=tty0 console=ttyS0,115200 |
Show boot output on VNC and serial consoles |
nomodeset |
Avoid graphics driver problems at boot |
systemd.unit=rescue.target |
Boot into rescue mode (one-off, set from the menu) |
init=/bin/bash |
Emergency root shell, bypassing init (password recovery) |
ipv6.disable=1 |
Disable IPv6 entirely |
Edit parameters for one boot (from the console)
At the GRUB menu (open the VNC console and reboot):
- Highlight the entry and press e.
- Find the line starting with
linux, and add your parameter at the end. - Press Ctrl+X or F10 to boot.
The change is temporary, so it’s safe for experiments and recovery. See Linux rescue mode.
If the menu doesn’t show, hold Shift (BIOS) or tap Esc (UEFI) right after the reboot starts.
Reinstall GRUB
If GRUB itself is broken, for example after a disk replacement on a RAID 1 dedicated server or after an interrupted update, reinstall it from the running system or a rescue environment.
BIOS systems:
sudo grub-install /dev/sda
sudo update-grub
UEFI systems (Ubuntu/Debian):
sudo apt install --reinstall grub-efi-amd64 shim-signed
sudo grub-install
sudo update-grub
From a rescue system, mount the installed system and chroot into it first:
sudo mount /dev/vda1 /mnt
for d in dev proc sys run; do sudo mount --rbind /$d /mnt/$d; done
sudo mount /dev/vda15 /mnt/boot/efi # if UEFI
sudo chroot /mnt
grub-install /dev/vda && update-grub
exit
On mirrored dedicated servers, install GRUB on both disks so either can boot.
Security: password-protect GRUB editing
Anyone with console access can edit kernel parameters and get a root shell (init=/bin/bash). On servers, the console is protected by your provider account, so this is usually acceptable. For extra protection, set a GRUB password with grub-mkpasswd-pbkdf2 and a password_pbkdf2 entry in /etc/grub.d/40_custom.
Quick reference
| Task | Command |
|---|---|
| Settings | /etc/default/grub |
| Regenerate | update-grub / grub2-mkconfig -o /boot/grub2/grub.cfg |
| List entries | grep menuentry /boot/grub/grub.cfg |
| Boot entry once | grub-reboot "entry" |
| Default kernel (RHEL) | grubby --set-default /boot/vmlinuz-… |
| Add parameter (RHEL) | grubby --update-kernel=ALL --args="…" |
| Current parameters | cat /proc/cmdline |
| Reinstall (BIOS) | grub-install /dev/sda |
Related: upgrade the kernel and uname.