Cleaning Up Unused Linux Kernels

7 Jun 2026·
赵吉忱
赵吉忱
· 5 min read
blog Year 2026

After installing another Linux kernel version, the old one usually stays installed. This is not a bug. It is a useful rollback path when the new kernel fails to boot, lacks a driver, or behaves strangely.

Once the system has been rebooted and confirmed healthy, though, keeping too many old kernels becomes a quiet kind of clutter. /boot gets noisy, GRUB entries pile up, and small boot partitions can eventually complain.

This is the checklist I would want before touching a real machine: confirm what is running, remove only the obsolete package set, refresh the boot menu, and leave a fallback kernel unless the host is truly disposable.

Caution

Run these commands as root, and do not remove the kernel currently running the system. If the target kernel is shown by uname -r, reboot into another kernel first.

Table of Contents

Confirm the running kernel

Start with the one kernel version that must not be removed.

uname -r

If this prints the version you planned to delete, stop here. Reboot, select a newer or otherwise known-good kernel from GRUB, then check again.

List installed kernel packages

On Red Hat-like systems such as RHEL, CentOS Stream, Rocky Linux, AlmaLinux, or Fedora, query RPM packages:

rpm -aq | grep kernel

On Debian-like systems such as Debian or Ubuntu, query installed linux-* packages:

dpkg -l | grep -Ei 'linux-image|linux-headers|linux-modules' | grep -Ei '^ii' | awk '{ print $2 }'

What you are looking for is the version suffix shared by the packages that belong to the old kernel. For example:

  • 6.8.5-301.fc40.x86_64 on a Fedora-style system.
  • 5.4.0-165-generic on an Ubuntu-style system.

I usually copy the suffix into a variable and print the matched packages before removing anything. It adds one boring step, and boring is excellent here.

Remove an old kernel on Red Hat-like systems

Use the package manager for the package removal itself, then clean the leftover modules directory if it remains.

deprecated_kernel='6.8.5-301.fc40.x86_64'

if [ "$(uname -r)" = "${deprecated_kernel}" ]; then
  echo "Refusing to remove the running kernel: ${deprecated_kernel}" >&2
  exit 1
fi

rpm -aq | grep kernel | grep -F "${deprecated_kernel}"
rpm -aq | grep kernel | grep -F "${deprecated_kernel}" | xargs -r dnf remove -y
rm -rf "/lib/modules/${deprecated_kernel}/"
dnf autoremove

If your system only has yum, use it for the final clean-up step:

yum autoremove

Then refresh GRUB configuration files under /boot:

ls -l /boot/ | grep rescue

find /boot/ -name 'grub.cfg' | while IFS= read -r file; do
  echo
  echo "Updating ${file}:"
  grub2-mkconfig -o "${file}"
done

Some systems also keep Boot Loader Specification entries under /boot/loader/entries/. If the removed kernel still has a stale .conf file there, remove that specific file.

ls -l /boot/loader/entries/

Be picky here. Delete only entries that clearly match the kernel version already removed.

Remove an old kernel on Debian-like systems

Again, set the version suffix first. apt purge removes the matching kernel packages and their package configuration; the separate apt autoremove then lets APT clean up dependencies that are no longer needed.

deprecated_kernel='5.4.0-165-generic'

if [ "$(uname -r)" = "${deprecated_kernel}" ]; then
  echo "Refusing to remove the running kernel: ${deprecated_kernel}" >&2
  exit 1
fi

dpkg -l | grep -Ei 'linux-image|linux-headers|linux-modules' | grep -Ei '^ii' | awk '{ print $2 }' | grep -E "${deprecated_kernel}$"
dpkg -l | grep -Ei 'linux-image|linux-headers|linux-modules' | grep -Ei '^ii' | awk '{ print $2 }' | grep -E "${deprecated_kernel}$" | xargs -r apt purge -y
rm -rf "/lib/modules/${deprecated_kernel}/"
apt autoremove
update-grub

On older Ubuntu releases, this pattern is especially handy after a manual kernel update: headers, image packages, modules, and modules-extra packages may all share the same version suffix.

Do a final sanity check

After clean-up, inspect what remains:

uname -r

# Red Hat-like
rpm -aq | grep kernel

# Debian-like
dpkg -l | grep -Ei 'linux-image|linux-headers|linux-modules' | grep -Ei '^ii' | awk '{ print $2 }'

The result I want is simple:

  • The running kernel is still installed.
  • At least one known-good fallback kernel remains, unless this is a tightly controlled image-building environment.
  • GRUB no longer shows entries for kernel packages that were already removed.
  • /lib/modules/ does not contain a directory for the removed kernel.

Limit future build-up

On Fedora/RHEL-like systems, DNF normally keeps only a small number of install-only packages, including kernels. If the host keeps too many kernels, check the configured limit:

grep -E '^installonly_limit=' /etc/dnf/dnf.conf

For most ordinary hosts, installonly_limit=3 is a reasonable balance: current kernel, one fallback, and one extra slot during updates. I would avoid setting it below 2.

On Debian/Ubuntu, old automatically installed kernels are often handled by:

apt autoremove

If a kernel package was manually marked as installed, APT may keep it. In that case, inspect the package names first and only then adjust the manual/auto mark or purge the exact old packages.

Keep the habit conservative

Kernel clean-up is not about being tidy for its own sake. It is about keeping the boot path understandable while preserving a rollback option.

For normal servers, I prefer keeping the current kernel and one previous known-good kernel. For disposable build hosts or image-making VMs, I may be more aggressive, but only after the new kernel has booted and the important workload has actually run.