1. Update OS
dnf update -y
  1. Reboot system if there were any updates
reboot
  1. Disable CentOS 8-specific modules (they are blocking kernel updates)
dnf module disable python36 virt
  1. Install CentOS 9 repositories. All CentOS 9 packages are listed here
dnf install https://mirror.stream.centos.org/9-stream/BaseOS/x86_64/os/Packages/centos-stream-release-9.0-22.el9.noarch.rpm https://mirror.stream.centos.org/9-stream/BaseOS/x86_64/os/Packages/centos-gpg-keys-9.0-22.el9.noarch.rpm https://mirror.stream.centos.org/9-stream/BaseOS/x86_64/os/Packages/centos-stream-repos-9.0-22.el9.noarch.rpm
  1. Run command to switch packages:
dnf --releasever=9 --allowerasing --setopt=deltarpm=false distro-sync -y
  1. Rebuild RPM database (this will chnage the backend to sqlite):
rpm --rebuilddb
  1. Disable subscription manager. Open file /etc/yum/pluginconf.d/subscription-manager.conf and set enabled to 0

  2. Reboot and verify

cat /etc/redhat-release
  1. Verify that the latest kernel is used (5.14+)
uname -a
  1. If not, use grubby to set the latest kernel as the default one, reboot the system and remove old kernels from CentOS 8:
# List all boot options
grubby --info=ALL

# Reflect the desired kernel in configuration
grubby --set-default vmlinuz-<version>.<arch>

# Make sure the index is also set in `/etc/default/grub` file

# Regenerate boot configuration
grub2-mkconfig -o /boot/grub2/grub.cfg

reboot

# Remove old kernels...

The instructions are inspired by CentOS 8 to CentOS Stream 8 migration guide and Fedora upgrade procedure