How to Downgrade a Package to a Previous Version with DNF

Use the dnf downgrade command with the --allowerasing flag to force installation of a previous package version.

Story / scenario opener

You ran a routine update and a critical package jumped two minor versions. The new release changed a configuration format, dropped a deprecated API, or introduced a regression that breaks your build pipeline. Your laptop wakes from sleep with a black screen because the graphics driver updated. You need to roll back to the version that worked yesterday.

What's actually happening

DNF treats your system as a forward-moving graph. Every repository points toward newer package versions, and the solver calculates the shortest path to the latest stable release. Downgrading breaks that forward momentum. When a package updates, it often pulls in newer libraries, updated configuration schemas, or patched dependencies. Pulling the main package backward leaves those newer dependencies floating in the system. DNF refuses to proceed by default because it cannot guarantee that removing the newer package will not orphan its dependencies or break other software that explicitly requires the newer version.

Think of it like a bridge that only extends forward. To retreat, you have to dismantle the newest sections and verify that the remaining structure can still support the traffic. The --allowerasing flag tells DNF to remove the conflicting dependencies instead of aborting the transaction. It is a deliberate override, not a safety net.

Fedora's release cadence is six months. The N-2 release goes end-of-life when N+1 ships. Plan upgrades on that cycle. Downgrading is a tactical maneuver for broken hardware or regression fixes, not a long-term strategy. Running dnf upgrade --refresh is the normal weekly maintenance command. dnf system-upgrade is for crossing major Fedora releases. They are different commands. Don't conflate them.

The fix

Start by checking which older versions DNF can actually reach. The package manager only sees versions present in your enabled repositories. If you disabled a repository or the version was purged from the mirrors, DNF cannot downgrade to it.

Here's how to list every available version of a package across your enabled repositories.

dnf repoquery --list <package-name> | grep -E "^<package-name>-[0-9]" | sort -V | tail -n 10 # WHY: repoquery fetches metadata without modifying the system. grep filters versioned packages. sort -V handles semantic versioning correctly. tail shows the most recent versions available.

Once you confirm the target version exists, run the downgrade command. DNF will automatically select the next available older version in the repository.

Here's the standard downgrade command with the dependency override flag.

sudo dnf downgrade <package-name> --allowerasing # WHY: downgrade targets the next older version in the repo. --allowerasing permits removal of packages that strictly depend on the newer version.

If you need a specific version rather than the next available one, use the install command with the full version string. This bypasses the downgrade logic and treats the older package as a fresh installation.

Here's how to target an exact version string when the automatic downgrade picks the wrong release.

sudo dnf install <package-name>-<version>-<release>.<arch> --allowerasing # WHY: install with a full NEVRA string forces that exact build. --allowerasing handles dependency conflicts that arise from installing an older release.

Always review the transaction summary before typing y. DNF will list every package it plans to remove, downgrade, or install. If the removal list includes core system components like glibc or systemd, abort the transaction. The dependency chain is too deep to safely reverse.

Run journalctl first. Read the actual error before guessing.

Verify it worked

The package manager reports success, but the running system might still hold the old binaries in memory or cache. Verify the installed version matches your target.

Here's how to confirm the exact package version currently on disk.

rpm -q <package-name> # WHY: rpm queries the local database directly. It ignores repository metadata and shows exactly what is installed.

If the package provides a service, check the unit status to ensure it loaded the correct binaries.

Here's how to verify the service is running the downgraded version without restarting.

systemctl status <service-name> # WHY: status shows the active state, recent journal lines, and the binary path. It confirms the system recognized the change.

If you downgraded a library or a compiler toolchain, run your build or test suite again. Memory caches and compiled artifacts often retain references to the previous version until they are rebuilt. Config files in /etc/ are user-modified. Files in /usr/lib/ ship with the package. Edit /etc/. Never edit /usr/lib/.

Reboot before you debug. Half the time the symptom is gone.

Common pitfalls and what the error looks like

DNF will stop the transaction if it detects a hard dependency conflict. You will see a transaction test error that lists the conflicting packages and the exact version mismatch.

Error: Transaction test error:
package python3-libs-3.12.7-1.fc40.x86_64 requires python3(x86-64) = 3.12.7-1.fc40, but none of the providers can be installed

The error means another package explicitly requires the newer version. The --allowerasing flag usually resolves this by removing the dependent package. If the flag is already present and the error persists, the dependency chain is circular or the target version is too old for your current repository state.

Another common issue is the version lock. If you previously used dnf versionlock to pin a package, DNF will ignore downgrade attempts and print a warning about locked packages. Remove the lock before proceeding.

Here's how to clear version locks that block downgrades.

sudo dnf versionlock delete <package-name> # WHY: versionlock maintains a separate database file. delete removes the pin so the solver can evaluate older versions again.

Configuration drift is the silent killer. Downgrading a package does not automatically revert your /etc/ files. The new version may have introduced new configuration keys or changed default values. The older binary will crash or misbehave if it encounters a configuration format it does not understand. Check the changelog for the target version and adjust your configuration files manually.

SELinux denials show up in journalctl -t setroubleshoot with a one-line summary. Read those before disabling SELinux. Downgrading can sometimes reset file contexts if the package manager fails to relabel. Run restorecon -Rv /etc/<config-dir> if you see permission denied errors after the downgrade.

Trust the package manager. Manual file edits drift, snapshots stay.

When to use this vs alternatives

Use dnf downgrade when you need to step back one version and accept automatic dependency resolution. Use dnf install <package>-<version> when you must target a specific release candidate or a version that skipped a minor update. Use dnf history undo when you want to reverse an entire transaction block rather than a single package. Use dnf versionlock when you need to prevent a package from updating during routine maintenance. Stay on the upstream release if you only deviate from the defaults occasionally.

Pick the tool that matches your rollback scope. Undoing a full transaction is safer than surgically removing one package from a tangled dependency graph.

Where to go next