• Python
  • Exact text checked with the real tool

certificate verify failed: Hostname mismatch, certificate is not valid for '…'

Also seen in: requests, urllib, pip, httpx

In one sentence

The certificate is trusted, but none of the names in its Subject Alternative Name list matches the hostname or IP address your code connected to.

Where you see it

In Python code that connects over HTTPS (urllib, requests, pip, http.client) after the chain has already been accepted. Since Python 3.7, OpenSSL does the name check during the handshake (ssl module documentation).

urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for 'api.internal.example.com'. (_ssl.c:1028)>

With requests:

requests.exceptions.SSLError: HTTPSConnectionPool(host='api.internal.example.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, "[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for 'api.internal.example.com'. (_ssl.c:1028)")))

If you connect by IP address, the wording changes:

certificate verify failed: IP address mismatch, certificate is not valid for '10.0.0.5'. (_ssl.c:1028)

What it means

A certificate lists the names it is valid for in its Subject Alternative Name (SAN) extension. Python compares the name in your URL with that list. The chain was trusted, so the certificate is genuine, but it was issued for other names. Python refuses it, because a valid certificate for another site proves nothing about this one.

Likely causes

You use a name the certificate does not list

Typical examples: a short internal name (api instead of api.internal.example.com), a load balancer’s own DNS name, localhost, or an old alias. See which names the certificate holds:

openssl s_client -connect api.internal.example.com:443 -servername api.internal.example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -ext subjectAltName
subject=CN=www.example.com
X509v3 Subject Alternative Name: 
    DNS:www.example.com, DNS:example.com

Fix: connect with a name from that list, or have the certificate reissued with every name clients use. For a private CA, add the names to the request:

openssl req -new -key server.key -subj "/CN=api.internal.example.com" \
  -addext "subjectAltName=DNS:api.internal.example.com,DNS:api" -out server.csr

You connect by IP address

An IP address matches only an IP entry in the SAN list (IP Address:10.0.0.5), never a DNS name. Use the DNS name, or reissue the certificate with an IP: entry if clients must use the address. Public CAs do not issue certificates for private (reserved) IP addresses.

The server sends the wrong certificate

Servers that host several sites pick the certificate from the name the client sends in SNI. If the name is unknown, the server falls back to a default certificate. Compare what you get with and without SNI:

openssl s_client -connect 192.0.2.40:443 -servername api.internal.example.com </dev/null 2>/dev/null | openssl x509 -noout -ext subjectAltName
openssl s_client -connect 192.0.2.40:443 -noservername </dev/null 2>/dev/null | openssl x509 -noout -ext subjectAltName

If both show the default site’s names, add a server_name api.internal.example.com; block with the right certificate in nginx (or a matching ServerName virtual host in Apache, or a hostname binding in IIS).

A wildcard does not cover this name

*.example.com covers exactly one label: api.example.com, but not example.com and not v2.api.example.com. Add the extra names as separate SAN entries.

The name is only in the Common Name

If the certificate’s SAN list contains a DNS name, the Common Name is ignored. If it has no DNS name in its SAN list (no SAN at all, or only IP addresses), Python still falls back to the Common Name, but browsers and Go do not (RFC 9525 says clients should use the SAN). Reissue such certificates with a SAN.

Check yours

Try it: Hostname matcherOpen the full tool

Runs in your browser. Nothing you paste is sent anywhere.

What do you have?

Paste the server’s certificate and type the hostname you connect to. The matcher shows which SAN entries match and why the others do not.

Learn why

In the gameLevel 9: Names and jobsName Registry, Keystone. In development

Early edition. Checked against the standards; an independent expert review is in progress. Found a mistake? Tell us.

Last reviewed Edition 0.9