dpkg Command in Linux: Complete Guide to Debian Package Management and Parameters

dpkg command in Linux and it perimeters

apt gets all the attention because it’s what you use day to day, but underneath every single install, upgrade, and removal on a Debian-based system, dpkg is doing the actual work. I didn’t really appreciate how much control dpkg gives you directly until I started troubleshooting a broken package state that apt alone couldn’t untangle. Understanding dpkg properly changed how I debug package problems entirely.

What dpkg Actually Is

dpkg (Debian Package) is the low-level package manager underlying the entire Debian package ecosystem. It’s responsible for the mechanics: unpacking .deb archive contents onto the filesystem, running pre/post install and removal scripts, tracking exactly which files belong to which package, and maintaining the package status database at /var/lib/dpkg/status. What dpkg does not do is resolve dependencies or fetch packages from the network — that’s entirely apt‘s job, layered on top.

I confirmed the version on my system:

dpkg --version
Debian 'dpkg' package management program version 1.22.6 (amd64).

Basic Syntax

dpkg [options] command

Here’s the core command set from dpkg‘s own help output:

-i|--install       <.deb file name>... | -R|--recursive <directory>...
--unpack            <.deb file name>... | -R|--recursive <directory>...
--configure         <package>... | -a|--pending
-r|--remove         <package>... | -a|--pending
-P|--purge          <package>... | -a|--pending
-V|--verify [<package>...]
--get-selections [<pattern>...]
--set-selections
-s|--status [<package>...]
-p|--print-avail [<package>...]
-L|--listfiles <package>...
-l|--list [<pattern>...]
-S|--search <pattern>...
-C|--audit [<package>...]

Installing a .deb Package Directly

This is the single most common reason to reach for dpkg instead of apt — you have an actual .deb file sitting on disk, downloaded manually or built yourself, and you want to install it directly:

sudo dpkg -i package-name_1.0.0_amd64.deb

The important caveat: dpkg does not resolve or fetch dependencies. If the package needs something not currently installed, dpkg -i will fail with unmet dependency errors. The standard fix is:

sudo dpkg -i package-name_1.0.0_amd64.deb
sudo apt install -f

apt install -f (fix-broken) reads the dependency requirements dpkg already recorded as unmet, then fetches and installs exactly those missing dependencies from the configured repositories, completing the process dpkg alone couldn’t finish.

Removing Packages

sudo dpkg -r package-name

Removes the package but leaves configuration files in place, matching apt remove‘s behavior underneath.

sudo dpkg -P package-name

Purges the package entirely, including configuration files — matching apt purge.

Listing Installed Packages

dpkg -l

I tested this directly and it produces a table with status flags, package name, version, architecture, and description:

Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                                 Version                              Architecture Description
+++-====================================-====================================-============-================================================================================
ii  adduser                              3.137ubuntu1                         all          add and remove users and groups
ii  adwaita-icon-theme                   46.0-1                               all          default icon theme of GNOME
ii  apt                                  2.8.3                                amd64        commandline package manager

The ii prefix means “installed and configured correctly” — that first character is the desired state (i for install), and the second is the actual current state (i for installed). Other combinations you’ll encounter: rc means removed but configuration files remain, un means unknown/not installed, and anything with uppercase letters (like iF or iH) signals a broken or incomplete state that needs attention.

You can filter with a pattern:

dpkg -l "nginx*"

Checking Package Status

dpkg -s nginx

Shows detailed status information for a specific package — installed version, dependencies, configuration file status, and the maintainer scripts’ last known state. I use this constantly when troubleshooting a package that apt reports as broken, since it shows the raw status flags directly.

Listing Files Owned by a Package

dpkg -L nginx

Lists every file the package installed onto the filesystem — binaries, config files, documentation, everything. Invaluable when you need to know exactly what a package touched, especially before manually removing something or investigating unexpected file changes.

Finding Which Package Owns a File

dpkg -S /usr/sbin/nginx

This is one of the commands I reach for constantly during troubleshooting — given a file path on disk, it tells you which installed package is responsible for it. Extremely useful when you find a mystery binary or config file and need to understand its origin.

dpkg -S /etc/nginx/nginx.conf

Verifying Package Integrity

sudo dpkg -V nginx

-V (--verify) checks the current state of a package’s installed files against the checksums recorded at install time, flagging anything that’s been modified since — extremely useful for detecting configuration drift or, in a security context, unauthorized file tampering.

Auditing for Broken Packages

dpkg -C

-C (--audit) scans the entire system for packages left in a broken, partially-installed, or otherwise inconsistent state, and reports what it finds along with suggested next steps.

Inspecting a .deb File Without Installing It

Before installing an unfamiliar .deb file, I always inspect it first:

dpkg -I package-name_1.0.0_amd64.deb

-I (--info) shows the package’s metadata — name, version, dependencies, maintainer, description — without touching the system at all.

dpkg -c package-name_1.0.0_amd64.deb

-c (--contents) lists every file that would be installed, again without actually installing anything. I use this combination religiously when working with a .deb from a source I don’t fully trust yet, or just to sanity-check a locally built package before deploying it.

Extracting Contents from a .deb File Manually

dpkg-deb -x package-name_1.0.0_amd64.deb /tmp/extracted/

This unpacks the actual file contents into a directory without running any install scripts or registering it with the package database at all — useful for inspecting file contents in isolation, or extracting a single file from a package without a full install.

dpkg-deb -e package-name_1.0.0_amd64.deb /tmp/control/

Extracts just the control information (maintainer scripts, dependency metadata) separately from the actual file payload.

Package Selections: Backup and Restore

One of my favorite lesser-known dpkg features is the ability to snapshot exactly what’s installed on a system, then reproduce that same state elsewhere:

dpkg --get-selections > my-packages-backup.txt

This dumps every package and its current selection state (install, deinstall, purge, hold) to a text file. To restore this state on another machine (after ensuring the same repositories are configured):

sudo dpkg --set-selections < my-packages-backup.txt
sudo apt-get dselect-upgrade

I’ve used this exact pattern when provisioning a new server that needed to match an existing one’s package set closely, well before configuration management tools like Ansible entered the picture for that purpose.

Configuring Pending Packages

Sometimes a package gets unpacked but its configuration step doesn’t complete (often due to an interrupted install):

sudo dpkg --configure -a

The -a (--pending) flag tells dpkg to go through and configure every package left in a pending state. This is one of the first commands I run when a system is reporting broken packages after an interrupted upgrade or a killed apt process.

Handling a Broken dpkg Lock

If dpkg was interrupted mid-operation (power loss, killed process), you might encounter a stale lock:

E: dpkg was interrupted, you must manually run 'sudo dpkg --configure -a'

Following that exact suggestion is almost always the correct fix. If a lock file genuinely needs manual removal (verify no dpkg/apt process is actually still running first):

ps aux | grep -i dpkg
sudo rm /var/lib/dpkg/lock-frontend
sudo rm /var/lib/dpkg/lock
sudo dpkg --configure -a

I only remove lock files after confirming no process is genuinely holding them — removing a lock while a process is legitimately running risks real database corruption.

Reconfiguring an Already-Installed Package

sudo dpkg-reconfigure tzdata

dpkg-reconfigure re-runs a package’s configuration scripts (the Debconf prompts), useful for revisiting settings chosen during initial install without a full reinstall — timezone, locale, and similar system-level settings are common targets for this.

Building Your Own .deb Package

For completeness, since it’s directly related: dpkg-deb --build lets you package a prepared directory structure into an installable .deb:

dpkg-deb --build mypackage-1.0/

This expects a specific directory layout, particularly a DEBIAN/control file describing the package metadata. I use this when packaging small internal tools for consistent, trackable deployment across a fleet of servers, rather than relying on raw make install (as discussed in my source-building guide).

Real-World Troubleshooting Workflow

Here’s the sequence I actually follow when a system reports package problems:

# 1. Check for anything broken
dpkg -C

# 2. Try to configure any pending packages
sudo dpkg --configure -a

# 3. Let apt attempt to resolve broken dependencies
sudo apt install -f

# 4. If a specific package is suspect, check its file integrity
sudo dpkg -V suspect-package

# 5. Check what files it owns, in case manual cleanup is needed
dpkg -L suspect-package

Comparison with apt

To be very direct about the division of labor: dpkg installs .deb files you already have and manages the local package database; it has no concept of repositories, downloading, or dependency resolution beyond reporting what’s missing. apt wraps dpkg, adding repository awareness, network fetching, and full dependency graph resolution. In practice, I use apt for essentially all routine work, and drop down to dpkg specifically when I have a .deb file in hand outside of a repository, or when I’m debugging a package database inconsistency apt isn’t giving me enough visibility into.

Security Implications

.deb packages run arbitrary maintainer scripts as root during install, exactly like apt-installed packages do, since apt is calling dpkg underneath either way. Only install .deb files from sources you trust. When inspecting an unfamiliar .deb before installing, I always check its control scripts specifically:

dpkg-deb -e suspicious-package.deb /tmp/control-check/
cat /tmp/control-check/postinst 2>/dev/null
cat /tmp/control-check/preinst 2>/dev/null

Reading these scripts before installing tells you exactly what will execute with root privileges during the install process.

Understanding dpkg’s Package Database Files

Everything dpkg tracks locally lives under /var/lib/dpkg/. Understanding this layout has helped me more than once when troubleshooting a genuinely corrupted package state:

  • /var/lib/dpkg/status — the master database of every package’s current status, version, dependencies, and configuration state. This single file is what dpkg -l and dpkg -s are actually reading from.
  • /var/lib/dpkg/info/ — contains per-package files: the list of files it owns (.list), and its maintainer scripts (.postinst, .prerm, .postrm, .preinst).
  • /var/lib/dpkg/available — historically tracked available packages from dselect; largely superseded by apt‘s own separate caching mechanism today.

I’ve occasionally had to hand-inspect /var/lib/dpkg/status directly (with extreme care, and always backed up first) when a package entry became corrupted in a way that normal dpkg/apt commands couldn’t cleanly recover from — this is very much a last-resort move, not a routine one, since manually editing this file incorrectly can make the package database inconsistent in ways that are much harder to fix than the original problem.

sudo cp /var/lib/dpkg/status /var/lib/dpkg/status.bak

I take this backup habitually before any manual intervention in this territory, even when I’m confident about what I’m doing.

Downgrading a Package with dpkg

Occasionally I need to roll back to a specific older version of a package I’ve kept a .deb copy of, or pulled from an archive:

sudo dpkg -i old-package-version_1.0.0_amd64.deb

dpkg doesn’t inherently object to installing an older version over a newer one — it just does it, unlike some package managers that treat downgrades as a special, blocked operation by default. This makes dpkg genuinely useful for emergency rollbacks when a newer version has introduced a regression, provided you kept the old .deb file around (which is exactly why I keep a small local archive of previously-installed .deb files for critical services, rather than relying solely on apt‘s cache, which gets cleaned periodically).

Comparing Package Versions Programmatically

dpkg --compare-versions 1.2.0 lt 1.3.0 && echo "1.2.0 is older"

This is genuinely useful inside shell scripts that need to make version-aware decisions — for example, only applying a specific workaround or configuration tweak if the installed package version falls below some known-problematic threshold.

INSTALLED=$(dpkg-query -W -f='${Version}' nginx)
if dpkg --compare-versions "$INSTALLED" lt "1.24.0"; then
    echo "nginx version is older than required, please upgrade"
fi

Compatibility Notes

dpkg is the foundational package tool for all Debian-derived distributions — Debian itself, Ubuntu and its many derivatives (Linux Mint, Pop!_OS, elementary OS), and embedded distributions like Raspberry Pi OS. RPM-based distributions (RHEL, Fedora, CentOS, openSUSE) use rpm as their equivalent low-level tool, with dnf/yum/zypper playing the role apt plays here.

Summary

dpkg is the engine underneath every apt operation, and understanding it directly gives you a level of visibility and control that becomes essential once you’re troubleshooting genuinely broken package states rather than just doing routine installs. The commands I reach for most — -l to list, -s for status, -L to see owned files, -S to find an owning package, and --configure -a to recover from interrupted installs — cover the vast majority of real troubleshooting scenarios you’ll encounter managing Debian-based systems over time.

References

  • man 1 dpkg
  • man 1 dpkg-deb
  • Debian Policy Manual, package format and control file specification (debian.org/doc/debian-policy/)
  • Debian Wiki: dpkg (wiki.debian.org/dpkg)
Total
0
Shares

Leave a Reply

Previous Post
how to perform automated backups in Linux

How to Perform Automated Backups in Linux

Next Post
apt command in Linux and it perimeters

apt Command in Linux: Complete Guide to Advanced Package Tool Commands and Parameters

Related Posts