# Nginx "key values mismatch": certificate and key don't match

> Nginx fails with key values mismatch when the private key does not belong to the first certificate in ssl_certificate. Compare the public keys and fix the file.

Source: https://ssl.sh/errors/nginx-key-values-mismatch/
Last updated: 2026-11-10

**`key values mismatch` means the [private key](https://ssl.sh/glossary/private-key/) Nginx loaded does not belong to the certificate it loaded.** Nginx checks the key against the first certificate in the `ssl_certificate` file, so the cause is either the wrong key file or a chain file in the wrong order.

## Quick fix

Different public key hashes mean the key and the certificate are not a pair.

Compare the public key inside the certificate with the public key derived from the private key:

```bash
openssl x509 -in /etc/nginx/ssl/example.com.crt -noout -pubkey | openssl sha256
openssl pkey -in /etc/nginx/ssl/example.com.key -pubout | openssl sha256
```

- **Hashes differ:** find the key that belongs to this certificate (or get the certificate reissued with a new CSR).
- **Hashes match:** the first certificate in the file is fine, so check the file you reference; run `nginx -T | grep -E "ssl_certificate(_key)?"` to see every path, including other `server` blocks and includes.

Then test and reload:

```bash
sudo nginx -t && sudo systemctl reload nginx
```

## Causes

### 1. The key belongs to a different certificate or CSR

This happens when a CSR is generated twice and the certificate is issued for the second one, when files from different renewals are mixed, or when a key from another domain is copied.

- **Confirm:** the hashes above differ. Check other candidate keys the same way; the CSR used for the order also contains the public key: `openssl req -in example.com.csr -noout -pubkey | openssl sha256`.
- **Fix:** use the matching key. If none matches, create a new key and CSR with the [CSR generator](https://ssl.sh/tools/csr-generator/) or OpenSSL and ask the CA to reissue.

### 2. The intermediate comes before the leaf in the chain file

Nginx uses the first certificate in `ssl_certificate` as the server certificate. If the CA bundle is concatenated first, Nginx compares your key with the intermediate's public key.

- **Confirm:** `openssl x509 -in fullchain.crt -noout -subject` shows the CA's name instead of your domain.
- **Fix:** rebuild the file with the leaf first:

```bash
cat example.com.crt ca-bundle.crt > fullchain.crt
```

The [chain builder](https://ssl.sh/tools/chain-builder/) produces a correctly ordered file.

### 3. Paths swapped or pointing to stale copies

- **Confirm:** `nginx -T` shows `ssl_certificate_key` pointing at an old copy, a backup directory, or the certificate file itself.
- **Fix:** point both directives at the current pair; for Let's Encrypt use the `live/` symlinks, which always point at a matching pair.

### 4. Hidden characters or merged files

Copy-pasting through Windows editors or web panels can merge two PEM blocks or drop a line.

- **Confirm:** `openssl x509 -in file -noout` or `openssl pkey -in file -noout` fails to parse.
- **Fix:** re-download the files from the CA or panel and convert line endings with `dos2unix` if needed.

## Fixes by environment

Whatever produced the files, the fix is the same: pair the key with the certificate issued for its CSR and put the leaf first. Apache reports the same problem as [AH02572](https://ssl.sh/errors/apache-ah02572-failed-to-configure-certificate/).

**Let's Encrypt (Certbot):**

```nginx
ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
```

**acme.sh:** do not point Nginx at `~/.acme.sh/`; run `acme.sh --install-cert -d example.com --key-file ... --fullchain-file ... --reloadcmd "systemctl reload nginx"` so both files are copied together on every renewal.

**Commercial certificates:** the CA sends the leaf and a CA bundle separately; concatenate leaf first. The key is the one generated with your CSR, usually on your server or in the panel where you created the CSR.

**ECDSA and RSA dual certificates:** when you configure two `ssl_certificate` / `ssl_certificate_key` pairs, each key must follow its own certificate in the same order.

**Docker / Kubernetes:** a TLS Secret's `tls.crt` and `tls.key` must also match; check them with the same commands after `kubectl get secret ... -o jsonpath`.

## Don't do this

- **Generate a "new key for the existing certificate".** It cannot match; you will only overwrite the correct key if it still exists somewhere.
- **Restart Nginx without `nginx -t`.** A failed start takes every site on the server offline, not only this one.
- **Email or chat the private key to whoever is debugging.** Share the public key hash instead; if the key was exposed, reissue the certificate with a new key.
