key values mismatch
The error "key values mismatch" means the private key configured does not correspond to the certificate configured — they are from two different key pairs. Confirm it by comparing the public key each one carries — `openssl pkey -in private.key -pubout | openssl sha256` and `openssl x509 -in certificate.crt -noout -pubkey | openssl sha256`. Different hashes confirm the mismatch. There is no way to repair it: a certificate certifies one specific public key, so you must find the matching private key or generate a new key, submit a new CSR and have the certificate reissued.
Confirm it #
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)= 5f2a8c1d4e7b...
Different output confirms the diagnosis. This test works for RSA and EC keys alike, unlike the
-modulus comparison you will find in older answers — see
why.
Find the right key #
Before reissuing, look for the key that does match. It is often still on the machine.
target=$(openssl x509 -in certificate.crt -noout -pubkey | openssl sha256)
for k in /etc/ssl/private/*.key /etc/ssl/private/*.pem; do
[ -e "$k" ] || continue
if [ "$(openssl pkey -in "$k" -pubout 2>/dev/null | openssl sha256)" = "$target" ]; then
echo "MATCH: $k"
fi
done Places worth checking:
- Other paths under
/etc/ssl/private/and/etc/pki/tls/private/ - The machine the CSR was originally generated on, which is often not this one
- A
.pfxthe certificate was delivered in — extract the key from it - Configuration backups, your secrets manager, or the previous host during a migration
Check you have the right certificate too #
Sometimes the key is fine and the wrong certificate got deployed — easy on a host serving several sites:
openssl x509 -in certificate.crt -noout -subject -ext subjectAltName If that names a different site than the one you are configuring, you have found the problem.
When the key is genuinely gone #
There is no recovery. Generate a new key, submit a new CSR, and have the certificate reissued:
openssl req -new -newkey rsa:2048 -nodes \
-keyout example.com.key -out example.com.csr \
-subj "/CN=example.com" \
-addext "subjectAltName=DNS:example.com,DNS:www.example.com" Most CAs reissue for the remaining term at no charge. With ACME, it is a single renewal command.
Avoiding it next time #
- Generate the key and CSR on the machine that will serve the certificate, and keep them together.
- Never regenerate the CSR after ordering — that creates a new key and orphans the certificate.
- Verify the pair as a deploy step, before reloading the service:
[ "$(openssl pkey -in private.key -pubout | openssl sha256)" \
= "$(openssl x509 -in certificate.crt -noout -pubkey | openssl sha256)" ] \
|| { echo "key/cert mismatch — refusing to reload"; exit 1; } Frequently asked questions
- Can I fix a mismatch without reissuing?
- Only by finding the correct private key. The certificate contains one specific public key, and only its counterpart can complete a TLS handshake. Nothing about the certificate can be edited — doing so would invalidate the CA's signature.
- What usually causes this?
- Regenerating the CSR (and therefore the key) after ordering the certificate, mixing up files during a multi-site deploy, or restoring a key from a backup that predates the last rotation.
- The files look identical in size — does that mean anything?
- No. Two RSA 2048 keys are the same size and completely unrelated. Only the public key comparison tells you anything.
- nginx -t passes but the browser still errors — is this the same thing?
- No.
nginx -twould catch a key mismatch. A config that tests clean but fails in browsers is usually a missing intermediate — see that error.
References
- openssl-pkey(1) — -pubout, which shows what the key actually carries
- openssl-x509(1) — -pubkey, for the certificate side