TL;DR
Your server is missing or has outdated CA (Certificate Authority) bundle files, so WordPress can't verify the remote server's SSL certificate. On a VPS, updating the CA certificates package takes about 30 seconds and fixes it permanently. On shared hosting, you'll need to point cURL at a fresh CA bundle manually โ or temporarily disable SSL verification on a local dev machine only.
What triggers this
WordPress calls external URLs constantly โ payment gateways, REST APIs, license servers, weather feeds. Each call goes through wp_remote_get() or wp_remote_post(), which internally uses PHP's cURL. cURL checks the remote server's SSL certificate against a list of trusted root CAs stored locally on your server. That list is outdated, missing, or pointing to the wrong file? You get:
cURL error 60: SSL certificate problem: unable to get local issuer certificate
Common triggers:
- Freshly provisioned VPS with a minimal OS image (no
ca-certificatespackage installed) - Old shared hosting with a stale CA bundle โ Let's Encrypt's root cert changed in September 2021 and broke a lot of older servers
- PHP compiled with
--with-curlpointing to a wrong or missingcacert.pem - Windows-based local dev (XAMPP and WAMP ship without a system CA bundle)
- Docker containers built from slim base images like
debian:slimoralpine
Diagnose first
Rushing in and toggling settings blindly wastes time. Spend 60 seconds confirming whether the issue is the CA bundle or something else entirely โ a self-signed cert, a broken remote URL, or a PHP config mismatch.
SSH into the server and run:
curl -v https://api.example.com 2>&1 | grep -E 'SSL|certificate|issuer'
If you see unable to get local issuer certificate at the OS level, the system CA bundle is the culprit. If curl works fine but WordPress doesn't, PHP's cURL is configured separately from the system one โ check where it's looking:
php -r "echo curl_version()['ssl_version'];"
php -r "$ch = curl_init('https://api.example.com'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_exec($ch); var_dump(curl_error($ch));"
Fix 1: Update system CA certificates (VPS / root access)
If you have root or sudo on the server, do this first. It fixes the problem at the OS level โ meaning every PHP app on the server benefits, not just WordPress.
Ubuntu / Debian:
sudo apt-get update
sudo apt-get install --reinstall ca-certificates
sudo update-ca-certificates
CentOS / RHEL / AlmaLinux:
sudo yum update ca-certificates
# or on newer systems:
sudo dnf update ca-certificates
After updating, restart PHP-FPM or Apache so PHP picks up the refreshed bundle:
# PHP-FPM
sudo systemctl restart php8.1-fpm
# Apache with mod_php
sudo systemctl restart apache2 # Debian/Ubuntu
sudo systemctl restart httpd # CentOS/RHEL
Trigger the failing API call from WordPress again to confirm it's resolved.
Fix 2: Point PHP's cURL at a fresh cacert.pem
No root access? This approach works on shared hosting, managed containers, and any environment where you can't touch system packages.
Grab the official Mozilla CA bundle that the curl.se team maintains and updates throughout the year:
cd /path/to/your/wordpress
wget https://curl.se/ca/cacert.pem -O cacert.pem
Tell PHP to use it. In php.ini:
[curl]
curl.cainfo = /path/to/your/wordpress/cacert.pem
[openssl]
openssl.cafile = /path/to/your/wordpress/cacert.pem
Can't edit php.ini? Add this to wp-config.php before the require line:
// Point cURL at a known-good CA bundle
define( 'CURL_CA_BUNDLE', __DIR__ . '/cacert.pem' );
Then create a must-use plugin to hook into WordPress HTTP requests:
<?php
// mu-plugins/fix-curl-ca.php
add_action( 'http_api_curl', function( $handle ) {
if ( defined( 'CURL_CA_BUNDLE' ) && file_exists( CURL_CA_BUNDLE ) ) {
curl_setopt( $handle, CURLOPT_CAINFO, CURL_CA_BUNDLE );
}
} );
Fix 3: Local dev only โ disable SSL verification
Never use this in production. Disabling certificate verification opens your site to man-in-the-middle attacks where an attacker can intercept and modify API responses.
For a local XAMPP, WAMP, or Docker environment where you just need to unblock development work:
// In your local wp-config.php only
add_filter( 'https_ssl_verify', '__return_false' );
add_filter( 'https_local_ssl_verify', '__return_false' );
Or pass it directly when making the API call:
$response = wp_remote_get( 'https://api.example.com/data', [
'sslverify' => false, // dev only!
] );
Fix 4: The remote server has a bad cert
Sometimes you're not the problem. The remote API itself has a self-signed or chain-incomplete certificate. Check with:
openssl s_client -connect api.example.com:443 -showcerts 2>/dev/null | openssl x509 -noout -issuer -subject -dates
If the issuer and subject are identical, it's self-signed. An incomplete chain usually means an intermediate cert is missing on the remote server. Your options:
- Contact the API provider โ it's their certificate configuration that's broken
- Manually add their root cert to your server's trust store
- Use
CURLOPT_CAINFOpointing to a file containing just their cert (practical only for internal APIs you control)
Verify the fix
Don't assume it worked. Drop this into a throwaway plugin or your theme's functions.php temporarily, then load a page while logged in as admin:
// Paste this into a throwaway plugin or the theme's functions.php temporarily
add_action( 'init', function() {
if ( ! current_user_can( 'manage_options' ) ) return;
$response = wp_remote_get( 'https://api.example.com/endpoint' );
if ( is_wp_error( $response ) ) {
error_log( 'Still broken: ' . $response->get_error_message() );
} else {
error_log( 'HTTP status: ' . wp_remote_retrieve_response_code( $response ) );
}
} );
Check wp-content/debug.log โ enable WP_DEBUG_LOG in wp-config.php if it's not there yet. HTTP 200 means you're done. Remove the snippet afterward.
Prefer the command line? Test PHP's cURL directly:
php -r "
\$ch = curl_init('https://api.example.com');
curl_setopt(\$ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt(\$ch, CURLOPT_VERBOSE, 1);
curl_exec(\$ch);
echo curl_error(\$ch);
curl_close(\$ch);
"
Quick notes
- The
cacert.pemfrom curl.se is refreshed several times a year. If you went with Fix 2, put a calendar reminder to re-download it every 6 months โ stale bundles will bite you again. - Let's Encrypt's old root cert (DST Root CA X3) expired on September 30, 2021. Servers still running Ubuntu 16.04 or CentOS 6 had it as their only trusted LE root, which is why dozens of LE-secured APIs suddenly started failing on those boxes around that date.
- Docker: add
RUN apt-get install -y ca-certificatesto your Dockerfile. Slim base images likedebian:slimomit it by design. - Cloudways, Kinsta, WP Engine: open a support ticket. You can't update system packages yourself, but their ops team can refresh the CA bundle on the node โ usually done within a few hours.

