// OSSeva Blog
SecurityHow to Verify PostgreSQL, MySQL and MariaDB Packages and Images Before You Install Them
The short answer
Verifying a database package takes three steps. Fetch the publisher's signing key from its own site, compare the key's full fingerprint with the one the publisher documents, then pin that key to that one repository so the package manager rejects anything it did not sign. After that, apt and dnf do the checking on every install and every update. For tarballs, verify the detached signature with gpg --verify. For container images, pin the digest and verify a signature if the publisher provides one.
The step people skip is the fingerprint check. A key downloaded over HTTPS from the same server as the packages proves less than it seems, because whoever controls that server controls both.
What a signature proves, and what it does not
A valid signature proves that the holder of a particular private key signed exactly these bytes. It does not prove the code is free of vulnerabilities, that the build was reproducible, or that the key was never stolen. It does close the most common gaps: a tampered mirror, a poisoned cache in your own repository manager, and a package pulled from somewhere it should not have come from. Pair signatures with an SBOM per build, covered in SBOMs and VEX for database servers.
PostgreSQL on Debian and Ubuntu (PGDG apt)
The PostgreSQL Global Development Group's apt repository is signed with the key published at https://www.postgresql.org/media/keys/ACCC4CF8.asc. Its fingerprint is B97B 0AFC AA1A 47F0 44F2 44A0 7FCC 7D46 ACCC 4CF8. Install the key into its own file and reference it with Signed-By, so it can sign this repository and nothing else:
sudo install -d /usr/share/postgresql-common/pgdg
sudo curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc --fail \
https://www.postgresql.org/media/keys/ACCC4CF8.asc
# Compare this output with the fingerprint above before going further
gpg --show-keys --with-fingerprint /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc
. /etc/os-release
sudo tee /etc/apt/sources.list.d/pgdg.sources <<EOT
Types: deb
URIs: https://apt.postgresql.org/pub/repos/apt
Suites: $VERSION_CODENAME-pgdg
Architectures: $(dpkg --print-architecture)
Components: main
Signed-By: /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc
EOT
sudo apt update
Do not use apt-key add. It trusts a key for every repository on the host, which is the opposite of what you want.
PostgreSQL on RHEL, Rocky and Alma (PGDG yum)
The PGDG repository RPM installs both the repository definition and the signing key. For EL 9 on x86_64 the key file is /etc/pki/rpm-gpg/PGDG-RPM-GPG-KEY-RHEL, with fingerprint D4BF 08AE 67A0 B4C7 A1DB CCD2 40BC A2B4 08B4 0D20, and the repository file turns on both package and metadata checks (gpgcheck=1 and repo_gpgcheck = 1). Confirm before the first install:
sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm
gpg --show-keys --with-fingerprint /etc/pki/rpm-gpg/PGDG-RPM-GPG-KEY-RHEL
grep -E 'gpgcheck|gpgkey' /etc/yum.repos.d/pgdg-redhat-all.repo
# For an RPM copied in by hand
rpm --checksig postgresql18-server-*.rpm
Keys differ by architecture and distribution family, and PostgreSQL 10 and older use separate archive keys. The key index at download.postgresql.org lists them all.
MySQL
Oracle signs MySQL packages with the MySQL Release Engineering key, ID B7B3B788A8D3785C, fingerprint BCA4 3417 C3B4 85DD 128E C6D4 B7B3 B788 A8D3 785C. The manual says this key signs 8.0.44 and later, 8.4.7 and later, and 9.5.0 and later; older packages use older keys.
One practical trap: the same key is published twice. The copy in RPM-GPG-KEY-mysql-2023 carries an expiry of 22 October 2025, and the copy in RPM-GPG-KEY-mysql-2025 carries the extended expiry of 23 October 2027. A host that imported the 2023 file can start failing signature checks for a reason that has nothing to do with tampering. Import the current file and check the fingerprint:
sudo rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2025
rpm --checksig mysql-community-server-8.4.12-1.el9.x86_64.rpm
# Tarballs and other downloads with a detached .asc signature
gpg --recv-keys B7B3B788A8D3785C
gpg --fingerprint B7B3B788A8D3785C
gpg --verify <package>.asc <package>
MariaDB
MariaDB Community Server packages are signed with the key 0xF1656F24C74CD1D8, fingerprint 177F 4010 FE56 CA33 3630 0305 F165 6F24 C74C D1D8. Since 2023 the same key signs the yum, dnf and zypper repositories and the source and binary tarballs, so one fingerprint covers every format. MariaDB Enterprise Server and MaxScale use different keys, documented on the same page.
# Debian and Ubuntu
sudo curl -LsSo /etc/apt/trusted.gpg.d/mariadb-keyring-2019.gpg \
https://supplychain.mariadb.com/mariadb-keyring-2019.gpg
gpg --show-keys --with-fingerprint /etc/apt/trusted.gpg.d/mariadb-keyring-2019.gpg
# RHEL, Rocky, Alma, SLES
sudo rpm --import https://supplychain.mariadb.com/MariaDB-Server-GPG-KEY
The Debian keyring file holds more than one MariaDB key. If you want the strictest setup, export only the Community Server key into its own keyring and reference it with signed-by as in the PGDG example.
Valkey and Redis
If you install Valkey or Redis from your Linux distribution's own repositories, the distribution's signing key covers them and the steps above apply with that key. If you run them from container images, the image checks below apply.
Container images
Docker Content Trust no longer works for Docker Official Images. Docker announced on 29 July 2025 that the signing certificates for those images would start expiring from 8 August 2025, that pulls with DOCKER_CONTENT_TRUST=1 would fail, and that users should move to Sigstore or Notation. For the official postgres, mysql, mariadb and redis images, that leaves two controls you can rely on today:
- Pin by digest. Deploy
postgres@sha256:..., notpostgres:18. A tag can be moved; a digest cannot. - Mirror and rescan. Pull into your own registry, generate an SBOM and scan there, and only allow the cluster to pull from that registry.
Where a publisher does sign with Sigstore, verify the signer's identity, not just the presence of a signature:
# Keyless signature: check who signed it and which identity provider vouched for them
cosign verify registry.example.com/db/postgres:18.6 \
--certificate-identity=release@example.com \
--certificate-oidc-issuer=https://accounts.example.com
# Signature made with a long-lived key the publisher gave you
cosign verify --key publisher-cosign.pub registry.example.com/db/postgres:18.6
Run the same check at admission time in Kubernetes, so an unsigned or wrongly signed image never starts, rather than only in CI.
Make it a control, not a habit
- Record every trusted key's fingerprint, owner, source page and expiry in one place, and review it when a key is rotated or extended.
- Check fingerprints against the publisher's documentation, not against the key file you just downloaded.
- Scope each key to its repository with
Signed-Byor per-repositorygpgkey. - Keep
gpgcheck=1on every repository and treat a disabled check as a finding. - Serve packages and images to production only from your own repository manager or registry, and verify on the way in.
How OSSeva signs its builds
OSSeva ships patched PostgreSQL, MySQL and MariaDB builds as signed DEB and RPM packages, tarballs and container images, and Redis builds as GPG-signed artifacts. Packages are GPG-signed, container images are signed with cosign through Sigstore, every release comes with SHA-256 checksums, and each customer receives a signed attestation document confirming the expected hash before deployment. Builds are delivered through your own repository manager or registry, so the controls above apply to them unchanged. The apt setup follows the same pattern as PGDG:
curl -fsSL https://packages.osseva.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/osseva.gpg
echo "deb [signed-by=/usr/share/keyrings/osseva.gpg] https://packages.osseva.io/postgresql $(lsb_release -cs) main" \
| sudo tee /etc/apt/sources.list.d/osseva-postgresql.list
The signing key details and verification commands are on the security page; compare the fingerprint there with the key you import. Coverage by engine is on the PostgreSQL, MySQL, MariaDB and Redis pages. Pricing is per cluster; book a discovery call for a quote.
Frequently asked questions
How do I verify a PostgreSQL package signature?
On Debian and Ubuntu, import the PGDG key, confirm its fingerprint is B97B 0AFC AA1A 47F0 44F2 44A0 7FCC 7D46 ACCC 4CF8, and reference it with Signed-By; apt then checks every package. On RHEL-family systems, keep gpgcheck=1 in the PGDG repository file, or run rpm --checksig on a copied RPM.
Why does MySQL's GPG key show as expired?
You probably imported RPM-GPG-KEY-mysql-2023, whose copy of the key expired on 22 October 2025. The same key with an extended expiry is published as RPM-GPG-KEY-mysql-2025; import that and the checks pass again.
Is checking the SHA-256 checksum enough?
Only if the checksum came from somewhere other than the file. A checksum on the same server as the download catches corruption, not tampering. A signature verified against a fingerprint you checked separately covers both.
Are Docker Official Images for PostgreSQL and MySQL signed?
Docker Content Trust signatures for Docker Official Images are retired, and Docker told users in July 2025 to plan a move to Sigstore or Notation. Until you can verify a signature for the image you use, pin it by digest and pull it only through your own registry.
What should we do when a vendor rotates its signing key?
Treat it as a change. Confirm the new fingerprint on the vendor's documentation, add the new key alongside the old one, and remove the old key only after every package you still install has been re-signed.
Tags
Related articles
How to Consolidate Open Source Database Support Contracts Without Migrating Anything
October 7, 2026OperationsWho Supports PostgreSQL, MySQL, MariaDB, Valkey and RabbitMQ Under One Contract?
October 7, 2026OperationsMySQL 8.0 End of Life: Dates, Consequences, and Your Options on AWS, Azure and Self-Managed
October 7, 2026Ready to get your open source under control?
Talk to an OSSeva engineer about CVE coverage, compliance, and migration support for your stack.