What Causes the “Certificate Verify Failed” Error in Python?
When Python tries to establish an HTTPS connection, it verifies the server’s SSL certificate against a list of trusted Certificate Authorities (CAs). If the certificate is self-signed (not issued by a trusted CA), Python throws the error:
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate in certificate chain (_ssl.c:1000)
This error is common in scenarios like:
- Working with internal APIs or servers.
- Using development environments with self-signed certificates.
- Testing HTTPS endpoints without valid certificates.
How to Trust a Self-Signed Certificate in Python?
If you control the server and have access to the self-signed certificate, you can add it to Python’s trusted certificate store.
Here’s how:
Step 1: Export the Self-Signed Certificate
- If you have the certificate file (e.g., server.crt), skip this step.
- If not, use OpenSSL to export the certificate:
openssl s_client -connect yourserver.com:443 -showcerts </dev/null 2>/dev/null | openssl x509 -outform PEM > server.crt
Step 2: Add the Certificate to Python’s CA Bundle
- Locate Python’s CA bundle file. On most systems, it’s at:
- Linux: /etc/ssl/certs/ca-certificates.crt
- macOS: /Applications/Python <version>/Install Certificates.command
- Windows: <Python installation path>\lib\site-packages\certifi\cacert.pem
- Append the self-signed certificate to the CA bundle:
cat server.crt >> /path/to/ca-certificates.crt
Step 3: Verify the Fix
- Restart your Python application and try the HTTPS request again.
How to Fix Certificate Verify Failed: Self-Signed Certificate in Certificate Chain [6 Easy Steps]
Here are some ways to fix the “python certificate verify failed: self-signed certificate in certificate chain” error caused by a self-signed certs:
- Disable Certificate Verification
- Specify Certificate Path
- Update SSL Context
- Add Certificate to Trusted CA Store
- Use Certifi to Manage Trusted CAs
- Use IP Address Instead of Domain
1. Disable Certificate Verification
You can disable certificate verification in Python requests using:
requests.get("https://example.com", verify=False)
And in urllib:
import urllib.request urllib.request.urlopen("https://example.com", cafile=None, capath=None, cadefault=False)
However, this is insecure and not recommended. It turns off protection against MITM attacks and should only be used for testing.
2. Specify Certificate Path
A better option is to provide the path to the self-signed certificate:
requests.get("https://example.com", verify="path/to/self-signed.crt")
This will tell Python requests to use that certificate to verify the SSL handshake.
For urllib:
import urllib.request urllib.request.urlopen("https://example.com", cafile="self-signed.crt")
This is safer than disabling verification completely.
3. Update SSL Context
You can also update the default SSL context in Python to trust the self-signed certificate:
import ssl ssl_context = ssl.create_default_context(cafile="self-signed.crt") requests.get("https://example.com", verify=ssl_context)
And for urllib:
import ssl import urllib.request ssl_context = ssl.create_default_context(cafile="self-signed.crt") urllib.request.urlopen("https://example.com", context=ssl_context)
This is a bit more flexible than providing the cert path each time.
4. Add Certificate to Trusted CA Store
Rather than providing the self-signed cert each time, you can add it to the trusted CA store:
On Linux/MacOS:
sudo cp self-signed.crt /usr/local/share/ca-certificates/ sudo update-ca-certificates
On Windows:
Import it to the system’s root certificates either through the Certificates MMC snap-in or using the CertUtil tool.
This will make Python and other applications trust the self-signed certificate automatically.
5. Use Certifi to Manage Trusted CAs
The Certifi package provides an up-to-date collection of trusted root CA certificates. You can use it to supplement or override the default CA store in Python.
For example, to use Certifi and disable the system CAs:
import certifi import ssl ssl_context = ssl.create_default_context(cafile=certifi.where()) requests.get("https://example.com", verify=ssl_context)
import certifi custom_ca = certifi.where() + "\n" + "self-signed.crt" requests.get("https://example.com", verify=custom_ca)
This gives you more control over trusted CAs in Python without modifying the system store.
6. Use IP Address Instead of Domain
If you connect to a server using a self-signed certificate locally, you can use the IP address instead of the domain name.
Certificate verification only happens for HTTPS connections based on domain names. Connecting directly to an IP does not trigger certificate validation.
For example:
requests.get("https://127.0.0.1:443", verify=False)
How to Bypass SSL Verification in Python Requests
If you’re using the requests library and need a quick workaround, you can bypass SSL verification. However, this is not recommended for production as it exposes you to security risks.
Example:
import requests
response = requests.get('https://yourserver.com', verify=False)
print(response.text)
Warning:
- Disabling SSL verification (verify=False) makes your application vulnerable to man-in-the-middle attacks.
- Use this only in development or testing environments.
Using a Custom CA Bundle to Fix SSL Errors
If you don’t want to modify the global CA bundle, you can specify a custom CA bundle in your Python code.
Step 1: Create a Custom CA Bundle
- Combine your self-signed certificate with the default CA bundle:
cat server.crt /path/to/ca-certificates.crt > custom-bundle.crt
Step 2: Use the Custom Bundle in Python
- Pass the custom bundle to the verify parameter in requests:
import requests
response = requests.get('https://yourserver.com', verify='/path/to/custom-bundle.crt')
print(response.text)
How to Ignore Self-Signed Certificate Errors in Python
If you’re working in a controlled environment and want to ignore SSL errors entirely, you can disable SSL verification globally.
Example:
import ssl import urllib.request # Disable SSL verification ssl_context = ssl.create_default_context() ssl_context.check_hostname = False ssl_context.verify_mode = ssl.CERT_NONE response = urllib.request.urlopen('https://yourserver.com', context=ssl_context) print(response.read().decode())
Warning:
- Disabling SSL verification globally is highly insecure and should only be used in trusted environments.
Best Practices for Handling Self-Signed Certificates in Python
While the above solutions work, it’s important to follow best practices to ensure security:
- Use Valid Certificates in Production:
- Avoid self-signed certificates in production environments.
- Use certificates issued by trusted CAs (e.g., Let’s Encrypt).
- Test with Staging Environments:
- Use self-signed certificates only in development or staging environments.
- Monitor SSL/TLS Configurations:
- Regularly update your server’s SSL/TLS configurations to avoid vulnerabilities.
Final Thoughts
Python giving a “certificate verify failed” error means it could not validate the server’s SSL certificate chain due to an untrusted self-signed cert.
The best solutions are correctly trusting the self-signed certificate or updating the SSL context rather than simply disabling verification.
Following the outlined troubleshooting steps can help identify and resolve tricky certificate issues using Python requests and other network libraries. Proper SSL certificate handling is important for maintaining security.
Frequently Asked Questions
Why am I suddenly getting certificate verification errors in Python?
Some common reasons you might suddenly get SSL certificate errors in Python include:
- The server certificate has expired and needs to be renewed.
- An intermediate CA certificate expired or was revoked.
- You’re connecting to a new server that uses a self-signed certificate.
- The web server was reconfigured to use a new certificate.
- The server disabled TLS 1.2 support, which Python requires.
Inspecting the full certificate chain on the server with openssl can help identify the issue.
How can I inspect certificates on Linux/MacOS?
Use the openssl command to view certificate details. For example:
# View certs provided by a server openssl s_client -connect example.com:443 -showcerts # View a certificate file openssl x509 -in certificate.crt -text -noout
This will let you inspect certificates, validation paths, expiration dates, etc.
What’s the difference between IP address and domain verification?
Using an IP address doesn’t trigger certificate validation. The domain name is required for the cert common name check.
So using an IP can workaround self-signed certificate errors, but eliminates the security of SSL. Only use IP in development environments when needed.
Can I disable certificate verification permanently in Python?
It is strongly recommended to keep SSL certificate validation enabled whenever possible. Disabling it permanently compromises security.
The best practice is to trust any required self-signed/private certificates at an OS/CA store level instead. That way, Python and other apps have the necessary certificates but keep verification intact.
Why Does Python Reject Self-Signed Certificates?
Python’s SSL module validates certificates against a list of trusted CAs. Self-signed certificates are not in this list, causing the CERTIFICATE_VERIFY_FAILED error.
Is It Safe to Disable SSL Verification?
No. Disabling SSL verification exposes your application to security risks like man-in-the-middle attacks. Use it only in trusted environments.
How do I generate a self-signed certificate for testing?
On Linux/MacOS, you can generate a self-signed certificate using OpenSSL:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
New-SelfSignedCertificate -DnsName "example.com" -CertStoreLocation "Cert:\CurrentUser\My"
Priya Mervana
Verified Web Security Experts
Priya Mervana is working at SSLInsights.com as a web security expert with over 10 years of experience writing about encryption, SSL certificates, and online privacy. She aims to make complex security topics easily understandable for everyday internet users.