Does this private key match this certificate?
To check whether a private key matches a certificate, compare the public key derived from each — `openssl pkey -in private.key -pubout | openssl sha256` and `openssl x509 -in certificate.crt -noout -pubkey | openssl sha256`. If the two hashes are identical, the key and certificate are a pair. This works for RSA, EC and Ed25519 alike, unlike the widely-quoted `-modulus` comparison, which is RSA-only and prints an empty modulus for EC keys — making two unrelated EC keys appear to match.
The check #
openssl pkey -in private.key -pubout | openssl sha256
openssl x509 -in certificate.crt -noout -pubkey | openssl sha256 Expected output
SHA2-256(stdin)= 9d4c1f2e8a3b... SHA2-256(stdin)= 9d4c1f2e8a3b...
Same hash means the certificate certifies that key. Different hash means these two files have nothing to do with each other.
As a one-liner that answers yes or no #
if [ "$(openssl pkey -in private.key -pubout 2>/dev/null | openssl sha256)" \
= "$(openssl x509 -in certificate.crt -noout -pubkey | openssl sha256)" ]; then
echo "MATCH"
else
echo "MISMATCH"
fi Including the CSR #
All three should agree if the certificate was issued from your CSR against your key:
openssl pkey -in private.key -pubout | openssl sha256
openssl req -in request.csr -noout -pubkey | openssl sha256
openssl x509 -in certificate.crt -noout -pubkey | openssl sha256 If the key and CSR match but the certificate does not, the CA issued against a different request — usually an older one.
Why not the modulus comparison #
The version you will find in most forum answers is:
openssl rsa -in private.key -noout -modulus | openssl md5
openssl x509 -in certificate.crt -noout -modulus | openssl md5 It is correct for RSA. The problem is what it does for anything else:
Comparing public keys has no such edge case. It is the same length of command and it is right for every algorithm, so there is no reason to use the older form.
When they do not match #
There is no repair. A certificate certifies one specific public key, and only the corresponding private key can complete a handshake for it. Your options are to find the correct key, or to generate a new key and CSR and have the certificate reissued.
Common causes:
- A CSR was regenerated (creating a new key) after the certificate was ordered.
- Several certificates for related hostnames got shuffled during a deploy.
- A key was restored from a backup taken before the last rotation.
- The certificate came from a PFX but the key came from somewhere else.
The error a web server gives is usually key values mismatch.
Related #
- Extract a key and certificate from a PFX — so both come from one source
- Check a key and certificate in your browser
Frequently asked questions
- Why not use the modulus comparison?
- Because it only works for RSA.
openssl ec -noout -modulusis not a valid combination andopenssl x509 -noout -modulusprints nothing for an EC certificate — so two unrelated EC keys produce two identical empty strings and appear to match. Comparing public keys avoids the trap entirely. - Can I check a CSR against a key the same way?
- Yes. Substitute
openssl req -in request.csr -noout -pubkeyfor the x509 command. The comparison is identical. - What if they do not match?
- You have files from two different key pairs, usually because a CSR was regenerated after the certificate was ordered, or because two certificates got mixed up. There is no way to make a mismatched pair work — find the right key, or reissue against the key you have.
- Does the certificate need to be valid for this check?
- No. This compares key material only. An expired or untrusted certificate will still match its key.
References
- openssl-pkey(1) — -pubout, which derives one side of the comparison
- openssl-x509(1) — -pubkey, the other side