Skip to content
Get Started

Why HTTPS Handshakes Are Slow From Mainland China (and How to Fix TLS, OCSP, and Certificate Chain Delays)

You’ve fixed DNS, moved to a server with premium routing, and your HTML is small. A user in Chengdu still waits close to a second before anything starts arriving, and the waterfall shows most of that time in a bar labeled “SSL” before a single byte of content.

That’s normal for a China route with default settings, and it’s fixable. The TLS handshake is a chain of round trips, and on a path where each round trip costs 70 to 200 milliseconds, with loss that turns some into retransmissions, every extra one hurts. Common certificate mistakes add round trips you didn’t know you were paying for.

Every round trip costs more on a China route

Before any content moves, an HTTPS connection has to complete several steps in sequence. The browser resolves DNS, opens a TCP connection, which takes one round trip, and then negotiates TLS on top of it.

With TLS 1.2, a full handshake takes two more round trips. With TLS 1.3, it takes one. Only after that does the browser send the actual HTTP request, which takes another round trip before the first byte of the response comes back.

Add it up for TLS 1.2: one round trip for TCP, two for TLS, and one for the request, so four round trips before any content. At 40 milliseconds, that’s 160 milliseconds and nobody notices. At 180 milliseconds, a realistic figure from a Tokyo or Singapore server to a provincial user on a congested route, it’s over 700 milliseconds. One lost packet during the handshake adds a retransmission timeout that can push it past a second.

That’s why handshake tuning matters so much more for China traffic than for a domestic audience. The handshake itself isn’t slower; the round trips are.

The deciding question: Is the handshake your bottleneck?

Before changing anything, find out whether connection setup or content delivery is where the time goes. They need different fixes.

From a test machine in China, or a testing service with China probes, use curl’s timing output:

curl -o /dev/null -s -w "dns: %{time_namelookup}\ntcp: %{time_connect}\ntls: %{time_appconnect}\nttfb: %{time_starttransfer}\ntotal: %{time_total}\n" https://example.com/

The gap between tcp and tls is your TLS handshake. The gap between tls and ttfb is your server’s response time plus one round trip. If the TLS gap is larger than two or three times your ping time, something beyond the basic protocol is adding round trips, and the sections below are where to look.

Cause 1: Still negotiating TLS 1.2

TLS 1.3 cuts the full handshake from two round trips to one. On a 180-millisecond path, that alone saves 180 milliseconds on every new connection.

Most modern browsers and mobile clients support TLS 1.3, but servers don’t always offer it, especially on older distributions or with carried-over configs. Check that your web server is built against a recent OpenSSL and that TLS 1.3 is enabled. Keep TLS 1.2 available for older clients, but make 1.3 the default path.

Cause 2: An incomplete certificate chain

Your server should send its own certificate plus the intermediate certificates that link it to a trusted root. If it sends only the leaf certificate, many clients will try to fetch the missing intermediate themselves, using the URL in the certificate’s Authority Information Access field.

That fetch is a whole extra connection to the certificate authority’s servers, mid-handshake. If those servers are slow to reach from China, or sit behind a CDN that performs poorly there, the handshake stalls while the browser waits. Some clients don’t fetch at all and just fail, which shows up as sporadic certificate errors on certain devices.

The fix is simple: configure your server with the full chain file, not just the certificate. With Let’s Encrypt, that’s fullchain.pem rather than cert.pem. Don’t include the root itself; clients already have it, and sending it only adds bytes.

Cause 3: OCSP checks to a slow responder

OCSP is how a client can check whether a certificate has been revoked, by asking the CA’s responder in real time. Browsers have mostly moved away from live OCSP checks, and Let’s Encrypt shut down its OCSP service on 6 August 2025 in favor of certificate revocation lists. Plenty of other CAs still include OCSP URLs, though, and some clients and libraries still query them.

When a client does query OCSP, it’s another connection to a server you don’t control, often hosted outside China and sometimes slow or unreliable from mainland networks. The handshake waits for the answer or a timeout.

OCSP stapling fixes this. Your server fetches the OCSP response itself, caches it, and includes it in the handshake, so the client never has to contact the responder. If your certificate has an OCSP URL, enable stapling and verify it’s working; if your CA no longer uses OCSP, there’s nothing to staple and nothing to wait on.

Cause 4: A certificate chain that’s too big

The server’s handshake messages have to fit in the TCP congestion window. On a new connection, Linux typically starts with a window of 10 segments, roughly 14 KB. If the certificates and handshake data exceed that, the server sends what fits, waits a round trip for acknowledgment, and then sends the rest.

A chain with a 4096-bit RSA leaf certificate and two RSA intermediates can come close to or exceed that limit, especially with a long list of names on the certificate. An ECDSA P-256 certificate is a fraction of the size of RSA 4096, and the matching ECDSA intermediates are smaller too.

Switching to ECDSA, trimming unnecessary names off the certificate, and not sending the root keeps the handshake inside one flight. If you need RSA for very old clients, most servers can serve both an ECDSA and an RSA certificate and pick per client.

Cause 5: No connection reuse

The cheapest handshake is the one you don’t do. Session resumption lets a returning client skip most of the handshake, using session tickets or TLS 1.3 pre-shared keys, and can reduce cryptographic work and handshake bytes. TLS 1.3 resumption without early data still takes a round trip; connection reuse avoids the handshake altogether.

Keep-alive and HTTP/2 matter just as much. A single long-lived HTTP/2 connection carries every request for a page, so the handshake cost is paid once. Every additional hostname a page loads from, such as separate static, image, API, and font domains plus third-party scripts, needs its own DNS lookup, TCP connection, and TLS handshake. On a China route, consolidating onto fewer hostnames is often worth more than any server tweak.

TLS 1.3 also offers 0-RTT early data, which can let a resuming client send an early request with the handshake. It’s a real saving, but early data can be replayed, so enable it only for requests your application explicitly treats as replay-safe. Even a GET can trigger side effects in a poorly designed app; check application behavior rather than relying on the method alone.

A note on SNI, ECH, and QUIC

Encrypted Client Hello hides the hostname a client is connecting to. Chinese network filtering has blocked its predecessor, ESNI, since 2020, and ECH connections from China have been reported as unreliable. Don’t depend on ECH for mainland users; make sure clients can fall back to a normal handshake quickly.

HTTP/3 runs over QUIC on UDP, and UDP is often deprioritized on congested China paths. Browsers usually try HTTP/3 only after learning about it from an HTTP/2 response, and fall back if it fails, but a broken or throttled QUIC path can still add delay. If your logs show HTTP/3 performing worse for Chinese users, it’s reasonable to stop advertising it for that traffic.

How to fix slow HTTPS handshakes on Nginx

Here’s a starting configuration covering the main points. Use Nginx 1.25.1 or newer for http2 on;, inside an HTTPS server block with listen 443 ssl;. Replace paths and YOUR_REACHABLE_DNS_IP with real values. Include the OCSP lines only for a certificate with an OCSP responder; ssl_trusted_certificate must contain the trust chain needed to verify the response:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_certificate     /etc/ssl/example/fullchain.pem;
ssl_certificate_key /etc/ssl/example/privkey.pem;

ssl_session_cache   shared:SSL:20m;
ssl_session_timeout 1d;

# Only if your certificate includes an OCSP URL
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/ssl/example/issuer-chain-and-root.pem;
resolver YOUR_REACHABLE_DNS_IP valid=300s;

keepalive_timeout 75s;
http2 on;

Then check the result. openssl s_client -connect example.com:443 -servername example.com -showcerts -status </dev/null shows the chain your server actually sends and whether a stapled OCSP response is included. SSL Labs and testssl.sh both flag incomplete chains, missing TLS 1.3, and stapling problems.

Finally, re-run the curl timing test from China and compare the TLS gap. On a well-tuned server it should be close to one round trip for new connections with less work for resumed sessions; a resumed TLS 1.3 handshake still normally takes one round trip unless early data is used.

What the network still decides

Server tuning reduces the number of round trips; it can’t make each round trip faster. A clean premium route keeps round-trip times stable and loss low, so the round trips you can’t eliminate don’t turn into retransmission timeouts. That’s where carrier routing and handshake tuning work together: one sets the cost per round trip, the other sets how many you pay for.

If the TLS gap is still large after tuning, look at the path itself. A traceroute that crosses a congested standard backbone like AS4134 at peak will add loss no TLS setting can fix. Our explainer on China Telecom’s premium path covers what changes when traffic stays on CTGNet instead.

Wrapping up

HTTPS handshakes are slow from mainland China mostly because every round trip is expensive, and common mistakes add extra ones: TLS 1.2 instead of 1.3, incomplete chains that trigger intermediate fetches, OCSP lookups to slow responders, oversized certificates that spill past the first flight, and too many separate connections.

Measure the TLS gap with curl from China, fix the server configuration, consolidate hostnames, and then judge the route. That order tells you which problem you actually have.

Thanks for reading! If your handshake is tuned and the route is still the bottleneck, Riven Cloud runs KVM VPS in Tokyo and Singapore on premium CTGNet, CUP, and CMIN2 paths to all three Chinese carriers, with a public Looking Glass in each location so you can check the route before you move.

Want to see how your site would perform? Compare plans or contact our team with questions.

Frequently asked questions about slow HTTPS from China

Why is the SSL or TLS part of my page load so slow from China?

The TLS handshake requires one or two round trips on top of the TCP connection, and round trips to mainland China are long and sometimes lossy. Configuration issues like incomplete certificate chains, OCSP lookups, or oversized certificates add even more round trips.

Does TLS 1.3 make a difference for Chinese visitors?

Yes. TLS 1.3 needs one round trip for a full handshake instead of two, which saves a full round trip on every new connection. On a 150 to 200 millisecond path, that’s a noticeable improvement.

Do I still need OCSP stapling?

Only if your certificate includes an OCSP URL. Let’s Encrypt ended its OCSP service in 2025, so its certificates don’t need stapling, but many other CAs still use OCSP, and stapling stops clients from contacting a responder that may be slow from China.

Should I use ECDSA or RSA certificates for China traffic?

ECDSA is usually better. ECDSA certificates and chains are much smaller than RSA 4096, which helps the handshake fit in the first TCP flight. You can serve RSA alongside it for very old clients.

Does HTTP/3 help visitors in mainland China?

It can, but results vary. QUIC runs over UDP, which is often deprioritized on congested China routes, so test it with real users and consider disabling it for Chinese traffic if it performs worse than HTTP/2.

How do I measure TLS handshake time from China?

Run curl with timing output from a machine or testing service in China. The difference between time_connect and time_appconnect is your TLS handshake time.

Share