PHP cURL “Recv failure: Connection was aborted” – Causes, Debugging, and Fixes

When accessing an external API or HTTPS endpoint, it is not uncommon to encounter the following PHP cURL error:

Recv failure: Connection was aborted

This issue is especially confusing when the same URL works perfectly from:

  • a web browser
  • the command line (curl)
  • tools like Postman

…but fails only from PHP code.

This article explains why this happens, how to diagnose the real cause, and provides battle-tested solutions applicable to enterprise and production environments.


What the Error Actually Means

The error:

Recv failure: Connection was aborted

means that:

  • A TCP connection was successfully established
  • The remote server closed the connection abruptly
  • PHP cURL did not receive a valid HTTP response

This is not a DNS error, nor a simple timeout. It is typically caused by server-side security policies, TLS negotiation issues, or request fingerprinting differences.


Why It Works in Browser or CLI but Not in PHP

This discrepancy is the key diagnostic clue.

Browsers and CLI curl:

  • Send User-Agent headers
  • Support modern TLS ciphers
  • Automatically negotiate HTTP/2 / ALPN
  • May pass through different proxies or networks

PHP cURL:

  • Uses libcurl + OpenSSL bundled with PHP
  • Often sends no User-Agent
  • May use older TLS versions
  • Runs under restricted firewall / SELinux / hosting rules

Many APIs silently drop connections that do not meet their security expectations.


Most Common Root Causes

1. Missing or Rejected User-Agent (Very Common)

Some API gateways explicitly reject requests without a User-Agent.

Symptom

  • Connection aborted immediately
  • No HTTP status code

Fix

curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0');

2. TLS / SSL Protocol Mismatch

PHP might be using:

  • TLS 1.0 / 1.1
  • Old OpenSSL
  • Unsupported cipher suites

The server closes the connection during the TLS handshake.

Fix
Force modern TLS:

curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);

Check OpenSSL version:

php -i | grep OpenSSL

3. Server Blocks “Bot-like” Requests

Many gateways (API Gateway, WAF, Cloudflare, Nginx security rules) block:

  • Requests without headers
  • Requests without Accept
  • Requests that look automated

Fix
Send minimal browser-like headers:

curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Accept: application/json',
    'Connection: keep-alive'
]);

4. HTTP/2 or ALPN Issues

Some PHP builds fail during HTTP/2 negotiation.

Fix
Force HTTP/1.1:

curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);

5. Proxy / Firewall / Hosting Restrictions

Common in:

  • Shared hosting
  • Corporate networks
  • Hardened Linux servers

The outbound connection is aborted mid-stream.

Checks

  • Compare server IP vs local machine IP
  • Test from the same server using CLI curl
  • Check firewall rules (iptables, firewalld)

6. Incorrect cURL Execution Order (Logic Bug)

A subtle but critical mistake:

curl_getinfo($ch); // ❌ before curl_exec()

curl_exec() must be called first, otherwise no request is executed.


Correct, Production-Ready PHP cURL Example

<?php

$url = 'https://example.com/api/v2/resource/123';

$ch = curl_init($url);

curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_CONNECTTIMEOUT => 10,

    // Security / compatibility
    CURLOPT_SSL_VERIFYPEER => true,
    CURLOPT_SSL_VERIFYHOST => 2,
    CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,

    // Headers
    CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; PHP-cURL)',
    CURLOPT_HTTPHEADER => [
        'Accept: application/json'
    ],
]);

$response = curl_exec($ch);

if ($response === false) {
    echo 'cURL error: ' . curl_error($ch);
} else {
    $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    echo "HTTP status: $status\n";
    echo $response;
}

curl_close($ch);

Advanced Debugging Techniques

Enable Verbose Output

curl_setopt($ch, CURLOPT_VERBOSE, true);

This reveals:

  • TLS handshake steps
  • Cipher negotiation
  • Exact moment the connection is aborted

Compare With CLI curl

Run on the same server:

curl -v https://example.com/api/v2/resource/123

Differences in:

  • TLS version
  • Headers
  • IP routing

…usually reveal the root cause.


When Disabling SSL Verification Does NOT Help

Setting:

CURLOPT_SSL_VERIFYPEER => false

does not fix:

  • TLS protocol mismatch
  • Cipher incompatibility
  • WAF blocking
  • Missing headers

It only bypasses certificate validation, not connection policies.


Best Practices for Stable API Calls in PHP

  • Always set a User-Agent
  • Force TLS 1.2+
  • Use HTTP/1.1 if HTTP/2 causes issues
  • Capture and log curl_error() and curl_getinfo()
  • Keep OpenSSL and PHP updated
  • Test from the same host as PHP runs

Summary

The error “Recv failure: Connection was aborted” is rarely a PHP bug. It is almost always caused by server security rules, TLS negotiation, or request fingerprinting.

By:

  • Sending proper headers
  • Forcing modern TLS
  • Executing cURL correctly
  • Matching browser behavior

…you can make PHP cURL requests as reliable as browser or CLI calls.

This article is inspired by real-world challenges we tackle in our projects. If you're looking for expert solutions or need a team to bring your idea to life,

Let's talk!

    Please fill your details, and we will contact you back

      Please fill your details, and we will contact you back