The SSL Handshake Deadlock
Nothing halts a productive coding session like a sudden SSL handshake failure. Your code might run perfectly on a Linux server, and the URL loads instantly in Safari, yet your Python script dies the moment it tries to fetch data. You're left staring at a traceback that ends in a stubborn error message.
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1129)
This isn't a code bug or a server failure. It's a configuration gap. Official Python.org installers for macOS don't use the system keychain for root certificates. Instead, they look for a specific certificate bundle that remains inactive by default. Essentially, Python is looking for a list of trusted authorities (like DigiCert or Let's Encrypt) and coming up empty-handed.
Diagnosing the Scope
Start by checking if the issue is limited to Python or affects your entire system. Run a quick test with curl in your terminal:
curl -I https://google.com
If you see a HTTP/2 200 response, your macOS network stack is healthy. The problem is isolated to Python's internal SSL module. Since version 3.6, Python on macOS has bundled its own OpenSSL copy, but it doesn't automatically link it to your system's trust store to prevent permission conflicts.
Solution 1: The "One-Click" Official Fix
If you used the .pkg installer from Python.org, a small utility script is already sitting on your hard drive. This 1KB script installs the certifi package—which contains a bundle of about 150+ root certificates—and creates the symbolic link Python needs.
Open your terminal and run this command for your specific version (e.g., 3.12 or 3.13):
/Applications/Python\ 3.12/Install\ Certificates.command
Not sure which version you're running? Use this wildcard command to find and execute the script automatically:
open /Applications/Python\ 3.*/Install\ Certificates.command
Wait five seconds for the process to finish. It will update pip, install certifi, and link the certificate paths.
Solution 2: The Environment Variable Workaround
Virtual environments or Homebrew installations sometimes skip the Applications folder entirely. In these cases, you can manually point Python to a valid certificate bundle. First, ensure the certifi library is present:
pip install --upgrade certifi
Next, determine the exact path of the certificate store:
python -c "import certifi; print(certifi.where())"
This usually returns a path like .../site-packages/certifi/cacert.pem. To make this change permanent, add an environment variable to your .zshrc (the default shell for modern macOS):
echo "export SSL_CERT_FILE=$(python -c 'import certifi; print(certifi.where())')" >> ~/.zshrc
source ~/.zshrc
Verifying the Fix
Does it actually work now? Run this snippet to verify that even basic Python libraries can now negotiate an HTTPS connection:
python3 -c "import urllib.request; print(urllib.request.urlopen('https://google.com').getcode())"
If it returns 200, you're back in business. If you rely on the requests library, try this as well:
python3 -c "import requests; print(requests.get('https://google.com').status_code)"
Best Practices for the Future
Relying on defaults can be tricky when moving between Windows, Linux, and macOS.
Keep these rules in mind:
- Post-Install Habits: Always run
Install Certificates.commandimmediately after installing a new Python version on macOS. - Virtual Environments: Each environment might need its own
certifiinstallation if it's isolated from system site-packages. - Avoid the "Verify=False" Trap: Never bypass this error using
verify=Falseorssl._create_unverified_context()in a production app. It disables encryption verification, leaving your data wide open to Man-In-The-Middle (MITM) attacks.

