Introduction / Why This Is Needed
GRUB (Grand Unified Bootloader) is the standard bootloader for most Linux distributions. It is responsible for selecting the operating system or kernel to boot, passing parameters to the kernel, and displaying the menu. Configuring GRUB allows you to:
- Change the default boot order (e.g., make Windows the primary OS).
- Set the timer for automatic boot or completely hide the menu.
- Add kernel parameters (
nomodeset,quiet splash,acpi=off) to resolve hardware issues. - Protect the menu from unauthorized editing with a password.
- Manually add an entry for an OS that GRUB did not detect automatically.
This guide covers the main scenarios for configuring GRUB 2 on modern systems.
Requirements / Preparation
- System Access: You must have superuser (
sudo) privileges. - Backup: Before editing the configuration, mandatorily create a backup of key files:
sudo cp /etc/default/grub /etc/default/grub.bak sudo cp -r /etc/grub.d/ /etc/grub.d.bak/ - Disk Partitioning Knowledge: Find out which partition your root (
/) and/bootfilesystems are on (if/bootis separate). Thelsblkorsudo fdisk -lcommands can help. - Understanding the Structure: GRUB 2 uses two types of files:
- Default Configuration:
/etc/default/grub(main variables). - Generation Scripts:
/etc/grub.d/(executable scripts that generate the menu). - Final Config:
/boot/grub/grub.cfg(DO NOT edit manually! It gets overwritten).
- Default Configuration:
Step 1: Basic Settings via /etc/default/grub
Open the main configuration file in a text editor (e.g., sudo nano /etc/default/grub). Here are the key parameters:
# Delay before automatically booting the selected item (in seconds)
GRUB_TIMEOUT=5
# Hide the menu if there is only one OS? (hidden - hide, menu - show)
GRUB_TIMEOUT_STYLE=menu
# Name of the default OS (usually corresponds to the name in the menu)
GRUB_DEFAULT=0 # 0 - first entry, "saved" - last selected
# Kernel parameters added to all Linux entries
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX=""
# Enable/disable recovery after failures (e.g., after a kernel update)
GRUB_DISABLE_OS_PROBER=false
# Color scheme (optional)
GRUB_COLOR_NORMAL="light-gray/black"
GRUB_COLOR_HIGHLIGHTED="white/blue"
What to change:
- To speed up boot, set
GRUB_TIMEOUT=2or0. - To remove the menu entirely (auto-boot), set
GRUB_TIMEOUT_STYLE=hiddenandGRUB_TIMEOUT=0. HoldShiftduring boot to invoke the menu. - To change the default OS, find its exact name in the future
grub.cfgor setGRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu, with Linux 6.5.0-27-generic"(use quotes and nesting via>). - For debugging, remove
quiet splashfromGRUB_CMDLINE_LINUX_DEFAULTto see kernel messages.
Step 2: Adding a Custom Entry (Manual Method)
If GRUB did not find the desired OS (e.g., another Linux system on a separate disk or an old Windows), add an entry manually.
- Create or edit the file
/etc/grub.d/40_custom. It already exists and contains examples. - Add a block for the new OS at the end of the file. Example for Windows on another disk:
How to determine### BEGIN /etc/grub.d/40_custom menuentry "Windows 10 (on /dev/sdb1)" { insmod ntfs set root='hd1,msdos1' # or 'hd0,gpt1' for GPT. Confirm via `ls` in grub rescue chainloader +1 }set root? Boot from a Live-USB, open the grub console (presscin the menu), and runls. Disks will behd0,hd1, etc., partitions(hd0,msdos1)or(hd0,gpt1). - For another Linux system, it's simpler to use
chainloaderorconfigfileif it has its own GRUB.
Step 3: Applying Changes and Updating the Configuration
After any change in /etc/default/grub or /etc/grub.d/, you must run:
sudo update-grub
This command:
- Runs scripts from
/etc/grub.d/in alphabetical order. - Detects installed kernels and OSes (if
GRUB_DISABLE_OS_PROBER=true, it skips detection). - Generates a new
/boot/grub/grub.cfgfile. - Prints a list of found menu entries.
Common Error: Forgetting to run update-grub. Changes will only take effect after regenerating the config.
Step 4: Password-Protecting the GRUB Menu (Prevent Editing)
This prevents accidental or malicious changes to boot parameters.
- Generate a password hash:
Enter and confirm the password. You will get a string likesudo grub-mkpasswd-pbkdf2grub.pbkdf2.sha512..... - Add the hash to the configuration. Open
/etc/grub.d/40_customand at the very end (before### END) add:
This creates aset superusers="root" password_pbkdf2 root grub.pbkdf2.sha512.10000.... # paste your long string hererootuser with a password. - Restrict editing permissions. In the same
40_customfile or a separate one (e.g.,01_users), wrap allmenuentryblocks in anifstatement:
A simpler (but less flexible) method: addif [ "${GRUB_MENU_ENTRY}" = "root" ]; then # All menuentries will be accessible only after entering the password set superusers="root" password_pbkdf2 root grub.pbkdf2.sha512.... fiGRUB_DISABLE_RECOVERY="true"to/etc/default/grubto hide the "Recovery" option, and usegrub-setpassword(not available in all distros). - Update the config:
sudo update-grub.
During boot, to select an entry or access the GRUB command line, press e or c—the system will prompt for a username (root) and password.
Step 5: Alternative Tools (Use with Caution)
For those who prefer not to edit files manually, graphical utilities exist:
- Grub Customizer (
sudo apt install grub-customizeron Debian/Ubuntu).- Pros: Convenient GUI for changing order, timer, and hiding entries.
- Cons: Can "break" the config during GRUB updates, stores changes in its own files, complicating debugging. Not recommended for servers and critical systems.
Conclusion: For reliability and understanding the process, manual editing via update-grub is preferable.
Step 6: Working with Kernel Boot and Parameters
Changing Kernel Parameters for a Single Session
- In the GRUB menu, select the desired entry and press
e(edit). - Find the line starting with
linuxorlinuxefi. These are the kernel parameters. - Add or modify parameters at the end of that line (e.g.,
nomodeset,noapic,acpi=off). - Press
Ctrl+XorF10to boot with these parameters (changes are not saved). - To make parameters permanent, find the
GRUB_CMDLINE_LINUX_DEFAULTvariable in/etc/default/grub, add the needed flags there, then runsudo update-grub.
Removing Old Kernels
Old kernels accumulate in /boot/ and can take up space. GRUB automatically shows all it finds. To clean up:
# Ubuntu/Debian
sudo apt autoremove --purge
# Fedora
sudo dnf remove $(package-cleanup --oldkernels --count=2)
After cleanup, sudo update-grub will update the menu.
Verifying the Result
- Reboot the computer.
- Ensure that:
- The GRUB menu appears (or doesn't, if configured as hidden).
- The timer works as set.
- The default OS boots automatically.
- All necessary OSes are present in the list.
- Kernel parameters (if added) are active (check with
cat /proc/cmdlineafter boot).
- If the system fails to boot but you see
grub>orgrub rescue>—refer to the "Possible Issues" section.
Possible Issues
Issue: After changes, the system does not boot, grub rescue> is visible.
Cause: GRUB cannot find its modules or config (e.g., after renaming the /boot partition).
Solution:
- Determine where your
/bootpartition is (vialsin grub rescue). - Manually set the root:
set root=(hd0,gpt1)(substitute your own). - Load the normal config:
insmod normal; normal. - If you booted, immediately fix
/etc/default/grub(possiblyGRUB_DISABLE_OS_PROBERor the path to/boot), then runupdate-grub.
Issue: update-grub does not find Windows.
Cause: Windows boots in UEFI mode while Linux uses Legacy (CSM), or vice versa. Or os-prober is disabled.
Solution:
- Ensure both OSes use the same BIOS/UEFI mode.
- Install
os-prober(sudo apt install os-prober), uncommentGRUB_DISABLE_OS_PROBER=falsein/etc/default/grub, and runsudo update-grubagain.
Issue: Changes in /etc/default/grub do not apply.
Cause: You edited the wrong file (e.g., from a chroot environment on another disk) or forgot update-grub.
Solution: Check that the correct file was modified (cat /etc/default/grub from your loaded system). Always run sudo update-grub after making changes.
Issue: After password-protecting GRUB, it asks for a password even to boot.
Solution: This is expected behavior if you set superusers globally. To have the password requested only when attempting to edit, you need more granular if-condition settings in the /etc/grub.d/ scripts. Often it's simpler to remove the password by editing 40_custom and regenerating the config.