The first time I bricked a server’s boot process, it was because I’d upgraded a kernel and forgotten that the initial RAM disk needed to be regenerated to match it. The system just sat there at boot, unable to find its root filesystem, because the drivers it needed to even see the disk controller lived inside an initrd image that no longer matched the new kernel. That experience is what pushed me to actually learn mkinitrd properly instead of treating it as some invisible thing package managers handled for me.
What an Initial RAM Disk Actually Is
Before I explain the command, I want to explain the problem it solves, because that context makes every option make sense.
When a Linux system boots, the kernel needs to mount the real root filesystem to continue booting into userspace. But that root filesystem might live on an LVM volume, a software RAID array, an encrypted partition, or a disk that needs a specific driver the kernel doesn’t have built directly into it. The kernel binary itself is often kept lean, with many drivers compiled as loadable modules rather than built in, to keep it small and flexible.
This creates a chicken-and-egg problem: the kernel needs modules to access the disk, but those modules live on the disk it can’t yet access. The solution is the initial RAM disk (initrd) or its modern successor, the initial RAM filesystem (initramfs). This is a small, temporary root filesystem, loaded into memory by the bootloader alongside the kernel, containing just enough drivers and tools to find, decrypt (if needed), assemble (if using RAID/LVM), and mount the real root filesystem. Once that’s done, the boot process performs a switch_root or pivot_root to hand control over to the real filesystem, and the temporary initrd content is discarded from memory.
mkinitrd is the tool historically used to build this image.
mkinitrd vs initramfs-tools vs dracut
Before diving into syntax, you should know that mkinitrd is somewhat legacy terminology and implementation now. There are three major lineages you’ll encounter:
mkinitrd— the original tool, historically used on Red Hat-based systems and still present (sometimes as a wrapper) on some distributions.dracut— the modern replacement on RHEL, Fedora, CentOS, and openSUSE, which actually provides amkinitrd-compatible wrapper script on some systems, while doing the real work throughdracutinternally.update-initramfs/mkinitramfs— the Debian/Ubuntu equivalent, part ofinitramfs-tools, which is the tool you’ll actually use day to day on those distributions even though people still colloquially say “make the initrd.”
I’ll cover the classic mkinitrd usage pattern in depth since that’s what’s being asked about, and note the modern equivalents where they matter, because in practice, if you type mkinitrd on a modern Ubuntu box, it won’t be there at all — you’ll need update-initramfs.
Basic Syntax
The traditional mkinitrd syntax looks like this:
mkinitrd [options] <initrd-image> <kernel-version>
For example, on a classic Red Hat-style system:
mkinitrd /boot/initrd-$(uname -r).img $(uname -r)
This tells mkinitrd to build an image for the currently running kernel version and save it to /boot.
Common Parameters
While exact flags vary slightly by distribution and version, these are the parameters you’ll see most consistently:
-f, --force Overwrite the target image if it already exists
-v, --verbose Print detailed progress information during creation
--preload=<module> Force a specific module to be loaded early in the initrd
--with=<module> Include an additional module not auto-detected
--omit-scsi-modules Skip inclusion of SCSI modules
--omit-raid-modules Skip inclusion of RAID modules
--builtin=<module> Assume module is built into the kernel, skip it
--fstab=<file> Use an alternate fstab file to determine filesystems
--nocompress Do not compress the resulting image
-i, --image-version Include kernel version string inside the image name
Forcing a Rebuild
If an initrd image already exists for that kernel version and you need to regenerate it (say, after adding a new storage driver or changing your LVM layout):
mkinitrd -f /boot/initrd-$(uname -r).img $(uname -r)
Verbose Mode for Troubleshooting
When something’s going wrong and I want to see exactly which modules are being pulled in:
mkinitrd -v -f /boot/initrd-$(uname -r).img $(uname -r)
Explicitly Including a Module
Sometimes auto-detection misses something, especially with less common storage or network hardware needed for network-based root filesystems (PXE boot scenarios, iSCSI roots, etc.):
mkinitrd --with=megaraid_sas -f /boot/initrd-$(uname -r).img $(uname -r)
Preloading a Module
If a module needs to be available very early, before other modules that depend on it:
mkinitrd --preload=dm_mod -f /boot/initrd-$(uname -r).img $(uname -r)
How mkinitrd Builds the Image Internally
Understanding the internals helps enormously with troubleshooting. Here’s the general process any of these tools (mkinitrd, dracut, mkinitramfs) follow conceptually:
- Detect the root filesystem type and location by reading
/etc/fstabor the current mount table, figuring out what’s mounted at/. - Determine required kernel modules by inspecting the hardware (via
/sysand/proc) and the filesystem type — for example, if root is on ext4 over LVM over a NVMe drive, it needs thenvme,dm-mod, andext4modules at minimum. - Build a minimal filesystem tree in a temporary directory, typically containing
/bin,/sbin,/lib/modules, and a minimal set of userspace tools likebusybox,udevd,lvm, ormdadmbinaries depending on what’s needed. - Copy in required kernel modules matching the target kernel version from
/lib/modules/<version>/. - Generate an init script (traditionally
/linuxrcin old-style initrd, or/initin initramfs) that will run as PID 1 briefly, mount necessary pseudo-filesystems (/proc,/sys,/dev), load modules, assemble any RAID/LVM devices, and eventually locate and mount the real root before callingswitch_root. - Package everything into a compressed cpio archive (for initramfs) or a compressed filesystem image (older initrd style, sometimes ext2-based), which the bootloader will load into memory alongside the kernel.
That’s why regenerating this file after a kernel upgrade matters so much — the module set inside the initrd has to match the module directory of the target kernel exactly, or the boot-time module loading step will fail silently or loudly, depending on how critical the missing module is.
Practical Workflow: Rebuilding After a Kernel Update
Here’s a workflow I follow whenever I manually compile or install a new kernel outside the package manager (which I cover more in my kernel rebuild guide):
# 1. Confirm the new kernel's modules are already installed
ls /lib/modules/
# 2. Generate the initrd for the specific new kernel version
mkinitrd -f /boot/initrd-5.15.0-custom.img 5.15.0-custom
# 3. Update the bootloader configuration to reference the new initrd
grub2-mkconfig -o /boot/grub2/grub.cfg
I always double check step 1 first — if depmod hasn’t been run and the module directory for that kernel version doesn’t exist yet or is incomplete, mkinitrd will silently produce a broken or incomplete image.
depmod -a 5.15.0-custom
Running depmod regenerates the module dependency map (modules.dep) for that kernel, which mkinitrd relies on to know what depends on what.
Debian/Ubuntu Equivalent Workflow
Since actual mkinitrd binaries are largely gone from Debian-family systems, here’s the equivalent I use there:
# Regenerate initramfs for the current kernel
sudo update-initramfs -u -k $(uname -r)
# Regenerate for all installed kernels
sudo update-initramfs -u -k all
# Create a brand-new image (rather than update) with verbose output
sudo update-initramfs -c -k 5.15.0-custom -v
RHEL/Fedora Modern Equivalent (dracut)
# Rebuild for the current kernel, forcing overwrite
dracut --force /boot/initramfs-$(uname -r).img $(uname -r)
# Add a specific driver module
dracut --force --add-drivers megaraid_sas /boot/initramfs-$(uname -r).img $(uname -r)
I mention these because if you go looking for mkinitrd on a modern Fedora or RHEL box, you may find it’s actually a thin compatibility wrapper around dracut, or missing entirely, depending on the release.
Inspecting an Existing initrd Image
Sometimes I need to verify what’s actually inside an initrd without regenerating it. For a compressed cpio-based initramfs:
mkdir /tmp/initrd-extract
cd /tmp/initrd-extract
zcat /boot/initrd-$(uname -r).img | cpio -idmv
This unpacks the archive so I can browse /tmp/initrd-extract/lib/modules and confirm whether the driver I need is actually present.
Common Use Cases
- After a manual kernel compile and install, so the new kernel has a matching boot-time module set.
- After changing storage configuration, such as converting a plain partition to LVM, adding a new RAID array, or enabling disk encryption with LUKS, all of which require their respective modules and tools present at boot time.
- After migrating disks or adjusting hardware, especially moving a system image to different virtualization or physical storage controllers (e.g., migrating from IDE emulation to VirtIO on a VM).
- Enabling early KMS (kernel mode setting) for graphics, sometimes requiring specific graphics drivers preloaded in the initrd for a smooth boot splash.
- Network boot / diskless setups, where the initrd needs network drivers and possibly an NFS or iSCSI root mount capability baked in.
Troubleshooting
System drops to an emergency shell / “Cannot find root filesystem” — this almost always means the initrd doesn’t contain the driver needed to see the disk. Boot from a rescue/live environment, chroot into the system, and regenerate the initrd with explicit --with=<module> for the missing driver.
Boot hangs waiting for a device — check whether LVM or RAID assembly tools are missing from the image; regenerate with the appropriate modules included, and verify /etc/mdadm/mdadm.conf or /etc/lvm/lvm.conf is consistent with what’s expected inside the initrd.
Old initrd used after kernel upgrade — verify the bootloader entry actually points to the newly generated initrd file with the matching version string. It’s a very common mistake to regenerate the initrd but forget to update GRUB’s configuration.
“Module not found” errors during boot but module exists on disk — this typically means depmod wasn’t run for that kernel version before generating the initrd, so the module dependency database inside the image is stale or missing entries.
Performance and Size Considerations
A bloated initrd containing every conceivable driver slows down boot time, since all that content needs to be loaded into RAM and unpacked before your real root filesystem is even reached. I usually let the automatic hardware detection do its job rather than force-including modules speculatively, unless I’m building a “universal” image intended to run across many different hardware profiles (common in enterprise imaging workflows where the exact target hardware isn’t known ahead of time).
Compression also matters. Modern tools default to a fast decompression algorithm (like lz4 or zstd) specifically because boot-time speed benefits more from quick decompression than from a marginally smaller file size.
Security Implications
The initrd runs as root with elevated privileges, very early, often before full security modules like SELinux or AppArmor are fully enforcing. If you’re building custom initrd images by hand, be deliberate about what scripts and binaries you include, since anything with write access to that image can effectively plant something that runs before most of your system’s security stack is even active. For encrypted root setups, the passphrase prompt itself happens inside the initrd environment, so verifying the integrity of that image (matching it against a secure boot signature, for instance) is an important defense against tampering, particularly on systems where physical access isn’t fully trusted.
Summary
mkinitrd (and its modern descendants, dracut and mkinitramfs/update-initramfs) solves the fundamental problem of getting a kernel from “just booted” to “can mount its real root filesystem,” by packaging a minimal, temporary environment with exactly the drivers and tools needed for that specific hardware and storage layout. Whenever you change kernels, storage configuration, or hardware in a way that affects early boot, regenerating this image is not optional — it’s required. Once you understand the module-dependency chain it’s built from, diagnosing a broken boot from a missing driver becomes a quick, methodical process instead of a guessing game.
References
man 8 mkinitrd(where present on your distribution)man 8 dracutand the Dracut project documentationman 8 update-initramfsandman 8 mkinitramfs(Debian initramfs-tools)- The Linux Kernel documentation on early userspace:
Documentation/admin-guide/initrd.rst - Red Hat Enterprise Linux documentation on boot process and dracut