Python — CERTIFICATE_VERIFY_FAILED

`SSLCertificateVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED]` means Python could not build a trusted path to the certificate a server presented. On macOS the usual cause is that Python ships its own CA bundle via the `certifi` package and does not read the system keychain — run the bundled `Install Certificates.command`. Elsewhere it is normally a corporate TLS-inspecting proxy or a private CA whose root is missing; point Python at a bundle containing it with the `SSL_CERT_FILE` or `REQUESTS_CA_BUNDLE` environment variable. Never fix it with `verify=False`.

Updated August 19, 2026 Verified against OpenSSL 3.5.7

Step 1 — is it Python, or is it the server? #

Test the server with a tool that has nothing to do with Python. If this reports a problem, the server is misconfigured and no Python change will help:

openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| grep "Verify return code"
Expected output
Verify return code: 0 (ok)

Code 20 means the server is not sending its intermediates — see that error. Code 0 means the server is fine and the problem is local to Python.

Step 2 — see which bundle Python is actually using #

import ssl, certifi
print(ssl.get_default_verify_paths())
print(certifi.where())

Then confirm the failing certificate really is absent from it:

openssl s_client -connect example.com:443 -servername example.com \
-CAfile "$(python -c 'import certifi; print(certifi.where())')" </dev/null 2>/dev/null \
| grep "Verify return code"

macOS — the most common cause by far #

A python.org installation on macOS does not read the system keychain. It expects certifi’s bundle to be installed by a script that does not run automatically:

/Applications/Python\ 3.12/Install\ Certificates.command

Adjust the version number to match. With Homebrew Python, reinstalling certifi usually achieves the same thing:

pip install --upgrade certifi

Corporate proxies and private CAs #

If the chain ends at a root your organisation controls, that root has to be in the bundle Python uses. Appending it to certifi’s bundle works but is undone by the next upgrade, so prefer a separate file:

cat "$(python -c 'import certifi; print(certifi.where())')" corporate-root.crt > /etc/ssl/certs/python-bundle.crt
export SSL_CERT_FILE=/etc/ssl/certs/python-bundle.crt
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/python-bundle.crt
Variable Read by
SSL_CERT_FILE ssl, urllib, most stdlib TLS
REQUESTS_CA_BUNDLE requests
CURL_CA_BUNDLE requests also honours this
pip config set global.cert pip specifically

Or per call, which is explicit and does not depend on the environment:

import requests
requests.get("https://example.com", verify="/etc/ssl/certs/python-bundle.crt")

In a container #

COPY corporate-root.crt /usr/local/share/ca-certificates/
RUN update-ca-certificates
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
ENV REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt

update-ca-certificates alone is not enough — Python will keep using certifi’s bundle unless the environment variables point it elsewhere.

What not to do #

Frequently asked questions

Why does curl work but Python fail on the same URL?
They use different trust stores. curl normally uses the system one; Python uses whatever certifi ships, or whatever SSL_CERT_FILE points at. A root installed for the system is invisible to Python unless it is in that bundle too.
Is verify=False acceptable?
No. It disables verification for that request entirely, so the connection is encrypted but unauthenticated and can be transparently intercepted. Use it once to confirm a diagnosis, never in code that ships.
How do I fix this on macOS?
Run the Install Certificates.command script inside /Applications/Python 3.x/. It installs certifi's bundle where Python expects it. A fresh python.org install ships without a usable trust store until you do.
Why does pip fail but python work?
pip may be using a different bundle, particularly inside a virtualenv or a corporate build image. Set it explicitly with pip config set global.cert /path/to/bundle.crt.

References