HTTPS needs the board to trust the server certificate, and it needs the right time to check it.
What the message means
A secure connection checks the certificate chain and its dates. A board with the wrong clock, or without the right root certificate, rejects the server.
Fix it in this order
- Sync the time first. See the NTP page.
- Give WiFiClientSecure the root certificate of the site with setCACert.
- Use setInsecure() only on your own network for testing, since it turns off the check.
- Root certificates expire and change. Update the one in your sketch when needed.
- Check the free memory. HTTPS takes more RAM than plain HTTP.
- Try the address in a browser to confirm the site itself works.
Why it happens
HTTPS needs the client to verify the server’s certificate chain against a trusted root. The ESP32 holds no root certificates unless you load one, so setCACert gives it the root that signed the site. Certificates also carry validity dates, and the client compares them with its own clock. Without correct time, a valid certificate can look expired or not yet valid.
Memory is the other common limit. A TLS handshake needs a large block of RAM, so a board short on heap can fail with an allocation error even when the certificate is correct. The usual order is to sync the time first, then load the right root certificate, then check memory. setInsecure() skips certificate checks, so it helps identify the cause but is not a finished design.
If you see this, do this
| You see | Do this |
|---|---|
| Works with setInsecure only | Certificate or clock problem. |
| Fails with out of memory | Free memory too low. |
Confirm the fix
- Print time(nullptr) after configTime and confirm it shows the current date, not a value from 1970.
- Connect with setCACert loaded and confirm client.connect returns true for the site over port 443.
- Print ESP.getFreeHeap() before and after the TLS connect to see how much memory the handshake uses on your board.
Common mistake: Assuming a certificate error means the server is misconfigured, when the board’s clock or a missing root certificate is usually the cause.
Related
Last reviewed: November 2026. These are the usual causes and the order that finds them fastest. Test on your own board; clones and cables differ.
Why this happens
A TLS connection begins with the server sending its certificate chain. The client checks that the chain ends at a root it trusts, that the name matches, and that the current date lies between the certificate’s start and end dates. The ESP32 trusts nothing until you load a root with setCACert(), and it gets its date from a clock that starts at 1970 after every power-up.
So two quiet failures are common. With no clock, a good certificate looks not yet valid, and the handshake fails. And the handshake needs a large block of heap for its buffers, so a board low on memory can fail even with perfect certificates. The error text from the library tells you which of these happened.
How to confirm the cause
- Print time(nullptr) after configTime(). A number near 1.7 billion means the clock is set; a small number means it is not.
- Print the error from the client with client.lastError(buf, size) after a failed connect. Text mentioning verification points to the certificate; text mentioning memory points to the heap.
- Temporarily call client.setInsecure() and test. If the call now works, the certificate or clock is the problem and the network is fine.
- Print ESP.getFreeHeap() before connecting. Under about 50 KB on a busy sketch is a warning sign.
- Open the same address in a PC browser and inspect the certificate’s issuer, to confirm which root signs it.
Worked example
This sketch sets the clock for India (UTC+5:30, 19800 seconds), waits for it, and prints the library’s error text on failure. rootCA holds the PEM text of the root certificate.
configTime(19800, 0, "pool.ntp.org");
time_t now = time(nullptr);
while (now < 1700000000 && millis() < 15000) { delay(200); now = time(nullptr); }
Serial.println(now);
WiFiClientSecure client;
client.setCACert(rootCA);
if (!client.connect("example.com", 443)) {
char err[100];
client.lastError(err, sizeof(err));
Serial.println(err);
}Replace example.com with your own host. The 1700000000 check only tests that the clock moved past 2023.
Common mistakes
- Using a leaf certificate in setCACert() when the root is needed, or the reverse for a pinned design.
- Putting the certificate in the sketch and forgetting it expires.
- Calling configTime() but not waiting for it to finish before connecting.
- Leaving setInsecure() in a finished project.
If this did not fix it
- Wrong server name: a certificate for another hostname fails the name check.
- A captive portal or proxy answers instead of the real server, so the certificate is not the one you expect.
- Old core version with an outdated bundle: update the board package.