redis/redis-py · critical · ConnectionError
received and expected certificates do not match
Error message
received and expected certificates do not match
What it means
Raised as a ConnectionError by ocsp_staple_verifier (redis/ocsp.py:165) when an `expected` certificate is supplied (pinned-cert mode) and the server's peer certificate does not match it. The function loads expected via x509.load_pem_x509_certificate and compares peer_cert != e; any mismatch aborts. This is an explicit pinning check — the caller asserted which cert should be present and the server presented a different one.
Solutions
- Update the pinned expected certificate to the server's current certificate if the rotation was legitimate.
- Confirm you are connecting to the intended endpoint (host/port) whose cert matches the pin.
- If the mismatch is unexpected, treat it as a possible MITM and investigate before trusting the new cert.
- Automate pin rotation so server and client pins are updated together to avoid stale-pin failures.
Example fix
# before - pinned expected cert is stale after rotation ocsp_staple_verifier(con, ocsp_bytes, expected=old_cert_pem) # ConnectionError: received and expected certificates do not match # after - update the pin to the new server cert (after validating the rotation is legitimate) ocsp_staple_verifier(con, ocsp_bytes, expected=new_cert_pem)
Defensive patterns
Strategy: try-catch
Validate before calling
from cryptography import x509
def peer_matches_pinned_cert(con, expected_pem):
peer = con.get_peer_certificate().to_cryptography()
expected = x509.load_pem_x509_certificate(expected_pem)
return peer == expected Try / catch
from redis.exceptions import ConnectionError as RedisConnectionError
try:
ocsp_staple_verifier(con, ocsp_bytes, expected=pin)
except RedisConnectionError as e:
if 'do not match' in str(e):
logging.critical('Peer cert does not match pinned cert - possible MITM or rotation: %s', e)
raise Prevention
- Update the pinned expected certificate whenever the server cert is legitimately rotated.
- Investigate unexpected pin mismatches as possible MITM before trusting the new cert.
- Automate coordinated pin rotation between server and client to avoid stale-pin failures.
- Confirm host/port before pin comparison to avoid cross-region cert mismatches.
When it happens
Trigger: Calling ocsp_staple_verifier(con, ocsp_bytes, expected=<pinned_cert_bytes>) where the server presents a different certificate than the pinned one. Common when the pinned cert was rotated and the client's expected value is stale, or when connecting to the wrong endpoint that serves a different cert.
Common situations: Certificate rotated on the server but the client's pinned expected cert not updated; connecting to a different node/region that uses a distinct cert; MITM presenting an attacker cert; pin file path points at an old cert; cert reissued with the same subject but different key/serial.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- delegate not authorized for ocsp signing
- failed to fetch issuer certificate
- failed to fetch ocsp certificate
- failed to retrieve a successful response from the ocsp…
- failed to valid ocsp response
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/cf7607f72f47cd8e.
Report an issue: GitHub.
Appendix: source
Thrown at redis/ocsp.py:165
"""
if ocsp_bytes in [b"", None]:
raise ConnectionError("no ocsp response present")
issuer_cert = None
peer_cert = con.get_peer_certificate().to_cryptography()
for c in con.get_peer_cert_chain():
cert = c.to_cryptography()
if cert.subject == peer_cert.issuer:
issuer_cert = cert
break
if issuer_cert is None:
raise ConnectionError("no matching issuer cert found in certificate chain")
if expected is not None:
e = x509.load_pem_x509_certificate(expected)
if peer_cert != e:
raise ConnectionError("received and expected certificates do not match")
return _check_certificate(issuer_cert, ocsp_bytes)
class OCSPVerifier:
"""A class to verify ssl sockets for RFC6960/RFC6961. This can be used
when using direct validation of OCSP responses and certificate revocations.
@see https://datatracker.ietf.org/doc/html/rfc6960
@see https://datatracker.ietf.org/doc/html/rfc6961
"""
def __init__(self, sock, host, port, ca_certs=None):
self.SOCK = sock
self.HOST = host
self.PORT = port
self.CA_CERTS = ca_certs
View on GitHub (pinned to 6a6b581b48)