
How to Load Linux Kernel Modules With Modprobe
Use modprobe, not insmod. When you load a module on Linux, modprobe reads the dependency map at /lib/modules/$(uname -r)/modules.dep, pulls in every module the target needs, and honors your blacklists and aliases. So if a module still refuses to load after modprobe, the fix is not a different command. The answer is in dmesg and modinfo output, and this guide shows you how to read it.
Last updated: 2026-07-21
What does it mean to load a kernel module?
Loading a module means inserting compiled kernel code into the running kernel without a reboot. That code runs in kernel space with full privileges, so a bad module can take the whole box down. Most drivers, filesystems, and network protocols ship as modules for exactly this reason: keep the core small, load the rest on demand.
The two commands people reach for are insmod and modprobe, and they are not equals. insmod takes a single .ko file path and inserts it, full stop. It resolves no dependencies, follows no aliases, ignores your blacklists. If the module needs another module first, insmod just fails with Unknown symbol in module.
modprobe is the tool you actually want. It works by module name rather than file path. It walks the dependency tree, loads prerequisites in order, and respects everything under /etc/modprobe.d. Reach for insmod only when you are testing one out-of-tree .ko and want to bypass all of that on purpose. For a fuller primer, see what a kernel module actually is.
How do you load a module in Linux?
Run modprobe with the module name and read the log. Here is the workflow I use every time.
- Confirm the module exists for your running kernel:
modinfo <name>. If that prints a file path and details, the module is present and built for you. If it errors, you have the wrong name or the wrong kernel tree. - Load it:
sudo modprobe <name>. No output means success.modprobealready pulled in any dependencies frommodules.dep. - Verify it loaded:
lsmod | grep <name>. The module and its dependencies should show up. - Read the kernel log:
sudo dmesg | tail -20orjournalctl -k. That tells you whether the driver bound to hardware or just sat there.
Step 4 is the one people skip. modprobe returning zero means the module inserted; it says nothing about whether the module did anything useful. A network driver can load cleanly and still fail to claim the card because the firmware blob is missing. The insertion succeeded; the job did not. The kernel log is where the difference shows up.
Put together, those four commands answer almost any load question. modinfo confirms the module exists, modprobe loads it with its dependencies, lsmod proves it went in, and dmesg shows what it did afterward. Running them in that order tells you both that the module loaded and whether it actually works.
To pass a parameter at load time, append it: sudo modprobe <name> option=value. More on that below.
Reading the list of loaded modules
lsmod is the fast inventory. It prints three columns: the module name, its size in bytes, and a "Used by" count with the names of dependent modules. That count is the reference count, and it matters before you unload anything.
Module Size Used by
xfs 2179072 1
libcrc32c 16384 1 xfs
Here libcrc32c shows 1 xfs, meaning xfs depends on it. Try to rmmod libcrc32c now and you get Module is in use. Unload xfs first, or use modprobe -r xfs, which handles the ordering for you.
lsmod is just a pretty view of /proc/modules. That file holds the same data in raw form, plus load addresses and state fields. Parse /proc/modules from a script when you need exact machine-readable output; use lsmod when you are reading with your eyes. For a deeper walkthrough, see how to list loaded kernel modules.
How do you set module options and parameters?
Pass them on the modprobe line for a one-off, or write them to /etc/modprobe.d to make them stick. The command-line form dies on reboot, so use it while you are still figuring out the right value.
sudo modprobe i915 enable_guc=3
To make that permanent, create a file like /etc/modprobe.d/i915.conf:
options i915 enable_guc=3
Any file in that directory ending in .conf gets read at load time. The options keyword names the module, then the parameters.
To see what parameters a module accepts, run modinfo -p <name>. That lists each parameter, its type, and a short description straight from the module. Guessing parameter names is a waste of time when modinfo prints the real list.
To check what a loaded module is using, look under /sys/module/<name>/parameters/. Each parameter is a file; cat it to read the live value. That is the ground truth. If the file says something different from your config, your config is not being read, and you go find out why.
Automatic loading with udev and systemd
Most modules load themselves, and systemd-udevd is why. When a device appears on a bus, the kernel emits a uevent carrying the device's identifiers. systemd-udevd catches it, builds a modalias string from those IDs, and asks modprobe to load whatever matches.
The match happens through modules.alias, generated by depmod. Every driver declares which device IDs it supports, and depmod bakes those into alias lines. So plugging in a USB adapter triggers a modalias lookup, finds the driver, and loads it with no action from you. That is the whole "it just works" story, and it is worth knowing because it is also how blacklists silently break things.
You can watch this live. Run udevadm monitor in one terminal, then plug in a device. You will see the kernel and udev events fire in real time, which is handy when a device plugs in and no driver shows up in lsmod.
For modules with no hardware to trigger them, systemd reads static lists at boot instead. That is the next section.
Loading modules automatically at boot
Drop the module name in a file under /etc/modules-load.d/. This is for modules that no hotplug event will ever load for you, like a filesystem helper or a tunable virtual device.
- Create
/etc/modules-load.d/mymods.conf. - Put one module name per line, no
modprobe, no options:
nf_conntrack
br_netfilter
- Reboot, or run
sudo systemctl restart systemd-modules-load.serviceto apply now. - Confirm with
lsmodand checkjournalctl -u systemd-modules-loadfor any load errors.
Parameters still belong in /etc/modprobe.d. This directory only says which modules to load; the options lines say how. Keep the two straight or you will stare at a config that looks right and does nothing.
One trap: a module needed to mount the root filesystem has to be in the initramfs too. If it is not baked into the initramfs, the system needs it before this service ever runs. Rebuild the initramfs after adding such a module (update-initramfs -u on Debian and Ubuntu, dracut -f on Fedora and RHEL). If boot itself is failing on module load, the "Failed to Start Load Kernel Modules" fix covers that specific error.
How aliases and blacklisting quietly change what loads
Aliases let you load a module by a friendly name, and blacklists stop a module from auto-loading. Both live in /etc/modprobe.d, and both change behavior without touching a single command you type.
An alias line maps one name to another:
alias net-pf-10 ipv6
Now modprobe net-pf-10 loads ipv6. The kernel uses this same mechanism internally to request drivers by capability instead of by name.
Blacklisting is where people get burned. A line like blacklist nouveau tells modprobe not to auto-load nouveau when udev asks for it. Here is the catch nobody mentions: blacklist does not stop an explicit modprobe nouveau or another module that depends on it. If you truly need it gone, add install nouveau /bin/true so any load attempt runs a no-op instead.
That distinction matters when you swap graphics drivers and the old one keeps coming back. The blacklist looked right; it just was not the whole fix. Safe blacklisting practices go through the edge cases in detail. The official modprobe manual page spells out every config keyword if you want the exact semantics.
Why does a module fail to load, and how do you diagnose it?
Read the kernel log first, not a forum. Run dmesg | tail -20 right after the failed modprobe, or journalctl -k for the same messages through systemd's log. The kernel almost always states the reason on the line where it refused.
The messages sort into a few real causes:
Unknown symbol in module– the module was built against a different kernel, or a dependency is not loaded.modprobehandles the dependency case; the version case does not.Invalid module format– the.kowas built for a different kernel version. Checkmodinfo <file> | grep vermagicagainstuname -r.Required key not available– signature enforcement rejected an unsigned module. This is Secure Boot or kernel lockdown at work; the module is fine.No such device/ driver loads but nothing binds – the module inserted but found no hardware or no firmware.
Run modinfo on the module to compare its vermagic string to your running kernel. A mismatch there explains most Invalid module format failures instantly. That one field tells you whether you are fighting a version problem or something else, so check it before you try anything clever.
If the failure is a missing signature, understand it before disabling protections. In kernel lockdown mode, only validly signed modules may be loaded, and that is deliberate. The fix is signing the module and enrolling the key. Turning lockdown off on a machine that needs it is the wrong move.
Resolving dependency and kernel version mismatches
Run sudo depmod -a when dependencies look broken. It scans /lib/modules/$(uname -r)/, reads each module's declared dependencies, and rebuilds modules.dep and modules.alias. If you dropped a new .ko into the tree by hand, modprobe cannot see it until depmod indexes it.
The harder problem is a version mismatch, and depmod will not save you there. The kernel checks each module's vermagic and symbol versions against the running kernel's application binary interface, or ABI. Build against 6.5 and boot 6.6, and the module is rejected even though the code is fine. The ABI moved under it.
The fixes, in order of preference:
- Rebuild the module against the kernel you are actually running. Install the matching
linux-headers-$(uname -r)first. - Boot the kernel the module was built for, if you still have it in GRUB.
- Use DKMS so the module rebuilds automatically on every kernel update, which is the durable answer for out-of-tree drivers.
If modprobe complains it cannot find the module tree at all, the directory for your running kernel is missing or incomplete. The "Missing Kernel Modules Tree" fix walks through rebuilding it. Never force a mismatched module in with insmod -f. Stripping the version check does not make the ABI compatible; it just moves the crash from load time to runtime, where it is much harder to trace.
FAQ
Can I unload a module that other modules depend on?
Not directly. rmmod refuses while the reference count in lsmod is above zero. Use modprobe -r <name> instead, which unloads the dependents in the correct order first. If something still holds it open, find the process or device using it before you force anything.
How do I load a module that is not in the standard tree?
Point insmod at the full path of the .ko file for a quick test, since it takes a file path directly. For anything permanent, copy the module into /lib/modules/$(uname -r)/extra/, run depmod -a, then load it by name with modprobe. That way dependency resolution and boot-time config work normally.
Does modprobe work the same on every distribution?
The command and its config format are identical across distributions, because they all use the same kmod tools. What differs is the initramfs tooling and header package names. Debian and Ubuntu use update-initramfs and linux-headers-*; Fedora and RHEL use dracut and kernel-devel. If a module load is not persisting across reboots on Ubuntu specifically, the persistent module load guide covers the distro quirks.
Why does a module load but the device still does not work?
Loading and binding are two separate things. A successful modprobe only means the code is in the kernel; whether the driver claimed your hardware is a separate question. Check dmesg for a bind line and for firmware requests. A driver waiting on a missing firmware blob loads silently and does nothing, and only the kernel log shows it.
How do I confirm a module is really loaded before I trust it?
Cross-check two sources. lsmod | grep <name> proves it is inserted, and journalctl -k or dmesg proves what it did after insertion. The first tells you it is present; the second tells you it worked. When those two agree, the module is genuinely doing its job.
