Controlling Debian Package Sources with APT Pinning
Learn how to use /etc/apt/preferences to pin Debian package versions across stable, testing, and unstable repositories without breaking dependencies.
30 Apr 2026, 22:49 UTC

The Problem: Unintended Upgrades from Mixed Repositories
When you enable testing or unstable repositories on a Debian stable system, APT's default behavior selects the highest available version number. This can silently upgrade core libraries and applications to versions that expect newer dependencies, leading to a partially broken system. The useful takeaway is that APT pinning lets you assign explicit priority values to each repository so the package manager prefers your chosen suite by default while still allowing targeted exceptions.
How APT Priorities Work
APT reads priority rules from /etc/apt/preferences and files in /etc/apt/preferences.d/. Each rule assigns a numeric priority to a set of package versions. Priorities at or above 1000 permit downgrades. Values from 990 to 999 force installation even if the version is not from the target release. Values from 500 to 989 prefer the version unless the target release has a newer one. Values from 100 to 499 allow installation but yield to versions from the target release. Values from 1 to 99 install only if the package is not already present. A priority of 0 or lower blocks the version. When two versions share the same priority, APT chooses the one with the highest version number. By default, an installed package has priority 100, while available repository versions typically receive 500, which is why adding a newer suite often causes mass upgrades.
Prerequisites
You need root privileges or a sudo-capable account. The system must have at least two suites configured in /etc/apt/sources.list or /etc/apt/sources.list.d/. Back up existing preferences with sudo cp /etc/apt/preferences /etc/apt/preferences.bak if the file exists. Familiarity with terminal-based package management is assumed. The file paths and preference syntax described here apply to Debian 11 (bullseye) and later.
Defining Pinning Rules in /etc/apt/preferences
Create a file such as /etc/apt/preferences.d/99-mixed-suite-policy. Each stanza uses three fields: Package, Pin, and Pin-Priority. The Package field accepts a package name or an asterisk for all packages. The Pin field matches a property such as release a=stable, release n=bookworm, origin deb.debian.org, or a specific version string. The Pin-Priority field sets the numeric threshold.
Example: Prefer Stable, Restrict Testing and Unstable
# /etc/apt/preferences.d/99-mixed-suite-policy
Package: *
Pin: release a=stable
Pin-Priority: 900
Package: *
Pin: release a=testing
Pin-Priority: 100
Package: *
Pin: release a=unstable
Pin-Priority: 1
In this configuration, stable versions receive priority 900, which strongly prefers them over other suites. Testing receives 100, equal to an installed package, so it will not replace stable unless explicitly requested. Unstable receives 1, meaning it is considered only when no other version exists. Note that a=stable matches the archive name; if your sources use codenames such as bookworm or trixie, use n=bookworm instead.
Example: Allow a Single Package from Unstable
Package: htop
Pin: release a=unstable
Pin-Priority: 999
This raises the priority of htop from unstable to 999, allowing it to be installed or upgraded even though the rest of the system remains pinned to stable. Because 999 is below 1000, APT will not perform a downgrade; it only permits an upgrade from unstable.
Applying and Verifying the Rules
After saving the file, run sudo apt-get update to refresh package metadata. Then inspect the effective policy for a package with apt-cache policy bash. Look for the Candidate line and the priority table. The candidate should originate from the suite you intended to prefer. To simulate an upgrade without changing the system, run apt-get -s dist-upgrade as a regular user; review the output for unexpected removals or version jumps from restricted suites.
Expected Checks
Confirm that apt-cache policy <package> shows the expected priority next to each repository. For example, stable entries should display 900 and unstable entries should display 1. Verify the installed state with dpkg -l <package>; the version string should match the stable repository unless you intentionally installed an exception. If you used apt-mark hold <package> to freeze a specific version, dpkg -l will show hold in the status column, but remember that holds and pinning are separate mechanisms.
Recovery Options When Pinning Breaks Dependencies
If a misconfigured priority causes APT to propose removing packages or leaves dependencies unresolved, first interrupt any running transaction. Run sudo dpkg --configure -a to complete any half-finished package configuration. Then run sudo apt-get install -f to attempt automatic repair of broken dependencies. If the system remains unusable, temporarily move the offending preferences file with sudo mv /etc/apt/preferences.d/99-mixed-suite-policy /root/ and run sudo apt-get update again. This restores default APT behavior. Once the system is consistent, reintroduce the rules one stanza at a time to isolate the conflict.
Limitations and Practical Considerations
Pinning controls candidate selection, but it does not prevent manual installation of a specific version with apt-get install package=version. Graphical package managers such as Synaptic or GNOME Software may not display pinning rules clearly, and some front-ends ignore them entirely. Pinning across suites with divergent library versions can still produce dependency conflicts; priority rules guide APT, but they cannot reconcile incompatible shared-library sonames. Always test changes with simulation flags before committing to a full upgrade.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.