You find a suspicious file in /usr/lib64 and need to know which package installed it. Or a service crashes and the error log mentions a library version that does not match what you expect. You need to trace a file back to its source package, check the installed version against the repository, or verify the signature of a binary before running it. The rpm command is the low-level tool for this, but using it correctly requires knowing the right flags and understanding how Fedora manages package metadata.
What's actually happening
Fedora uses RPM as its package format and database backend. The rpm command talks directly to the RPM database stored in /var/lib/rpm. When you query a package, you are reading metadata that was recorded during installation. DNF handles dependencies, downloads, and transaction safety. RPM handles the actual file placement and metadata storage. You use rpm to inspect what is already on the system. You use dnf to change the state of the system. Querying with rpm is fast because it reads the local database. It does not contact the network.
The RPM database lives in /var/lib/rpm. It is a Berkeley DB environment. Multiple processes can read it simultaneously. Writes are locked. If you see error: cannot open Packages database in /var/lib/rpm, another process like dnf or yum is likely holding the lock. Wait for the other process to finish. Do not force the lock. Forcing the lock can corrupt the database and require a rebuild with rpm --rebuilddb.
Query with rpm. Change with dnf. Mixing them up breaks the database.
How to query package information
Here is how to check the version, release, and architecture of an installed package.
rpm -qi firefox # -q queries the database, -i prints the full info block
Use this command to find which package owns a specific file path.
rpm -qf /usr/bin/firefox # -f queries by file path to find the owning package
List every file installed by a package to check for missing components or to locate a specific library.
rpm -ql firefox # -l lists all files installed by the package
Check the package changelog to see what bugs were fixed in a specific version.
rpm -q --changelog firefox | head -20 # --changelog shows history, pipe to head limits output to first 20 lines
Verify file integrity against the database to detect modifications or corruption.
rpm -V firefox # -V verifies files against database records
Convention aside: Scripts often use rpm -qa to list all installed packages because it is faster and produces cleaner output than dnf list installed. The rpm -qa command reads the database directly. It does not parse repository metadata. Use rpm -qa in automation. Use dnf list installed when you need human-readable output with repository sources.
Run rpm -qf on the file you are debugging. The package name is the first clue to the solution.
Verify the query worked
A successful query returns structured text. The rpm -qi output includes Name, Version, Release, Architecture, and Install Date. If the package is not installed, rpm prints package <name> is not installed. This is a definitive answer. It means the package is not in the local database. It does not mean the package does not exist in the repository. Check the repository with dnf info if you need to install it.
If rpm says not installed, trust it. The database is the source of truth for what is on disk.
Common pitfalls and what the error looks like
The rpm -q command will print package python39 is not installed if the package is missing. This error is accurate. The package is not in the local database. Use dnf info python39 to see if it is available for installation.
The rpm -qf command will print file /home/user/script.sh is not owned by any package for files in user directories. RPM only tracks files installed by packages. Files in /home, /tmp, /var/tmp, and /root are never owned by RPM. Do not use rpm -qf on user data.
When running rpm -V, output like S.5....T. c /etc/nginx/nginx.conf indicates a file has changed. The S means size changed, 5 means MD5 checksum changed, T means modification time changed, and c means it is a config file. This is normal for configuration files. It does not indicate a broken package.
The rpm -V command prints a nine-character string for each file that differs from the database. Each position represents a specific attribute. The first character is S for size. The second is M for mode. The third is 5 for MD5 checksum. The fourth is D for device. The fifth is L for symbolic link. The sixth is U for user. The seventh is G for group. The eighth is T for modification time. The ninth is P for capabilities. A dot . means the attribute matches. A letter means it differs. A c prefix indicates a configuration file. A %doc prefix indicates documentation. Understanding these flags helps you distinguish between a harmless config change and a compromised binary.
Read the verification flags. A changed config file is expected. A changed binary is not.
When to use rpm versus dnf
Use rpm -qi <package> when you need the exact version and architecture of a package already installed on the system.
Use dnf info <package> when you want to see available versions in the repositories or check package details before installation.
Use rpm -qf <path> when you have a file path and need to identify the package that installed it.
Use dnf provides <glob> when you are looking for a file or capability but do not know the package name.
Use rpm -V <package> when you suspect files have been modified or corrupted and need to verify integrity against the database.
Use rpm -q --changelog <package> when you need to check what bugs were fixed in a specific version to determine if an upgrade is necessary.
Query locally with rpm. Search globally with dnf. Pick the tool that matches your scope.