How to Fix OpenSSL SSL_read Connection Reset Errors in PHP Guzzle Requests

When connecting PHP backend services to external APIs, Guzzle is the standard HTTP client. However, when performing heavy volume requests or integrating with legacy servers, developers often run into cURL error 56: OpenSSL SSL_read: Connection reset, errno 104. This error means that the SSL handshake or communication channel was abruptly closed by the remote server during a read operation. This guide breaks down the causes of this error and provides steps to resolve it.
1. Diagnosing the SSL Connection Reset Error
The connection reset error typically stems from one of three areas:
- Keep-Alive Timeouts: The remote server closes inactive connection channels, but Guzzle attempts to reuse the connection.
- SSL Protocol Mismatches: The remote server requires a specific TLS version, but the local OpenSSL library defaults to a higher or unsupported version.
- Payload Sizes: The request payload exceeds buffer limits, causing the server's firewall to drop the connection during the SSL handshake.
2. The Fix: Adjusting Guzzle Curl Options
To resolve these connection issues, you must configure Guzzle’s underlying cURL configurations. Specifically, disabling connection reuse, adjusting timeouts, and forcing standard TLS versions usually fixes the problem.
use GuzzleHttp\Client;
$client = new Client([
'timeout' => 30.0,
'curl' => [
CURLOPT_FORBID_REUSE => true, // Force close connection after request completes
CURLOPT_FRESH_CONNECT => true, // Request a clean connection channel
CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2, // Force TLS 1.2 compatibility
]
]);
$response = $client->get('https://api.example.com/data');
3. Fixing MTU Size Issues
In containerized environments (such as Docker, Kubernetes, or server instances behind VPN gateways), the Maximum Transmission Unit (MTU) size of network packets can cause SSL handshakes to fail. If the MTU size is too large, routers drop the packets, resulting in a connection reset. Setting a lower MTU size (e.g. 1400 instead of 1500) resolves this.
# Temporary fix on server instances
sudo ifconfig eth0 mtu 1400
4. Summary Checklist
Always log the exact cURL debug output when troubleshooting Guzzle errors. Setting 'debug' => true in your client instantiation provides deep insight into the connection lifecycle, helping you isolate network drops from configuration issues.