ESP32 TLS memory usage, and how to reduce it

One TLS connection is usually the largest single consumer of heap in ESP32 firmware. Espressif's own figure is about 35 KB. With the right options the same connection idles at about 24 KB, and these are the options.

Where the memory goes

mbedTLS keeps one buffer for records coming in and one for records going out. By default the incoming one is 16 KB, because a server is allowed to send records that large, and the outgoing one is 4 KB. On top of that come the handshake state, the certificate chain being checked, and the session itself. The handshake is the peak: for a second or two the device needs noticeably more than it does afterwards.

The options that matter

OptionWhat it doesWhat it costs
CONFIG_MBEDTLS_DYNAMIC_BUFFERAllocates the record buffers when a record is being handled and frees them after, and releases handshake data once the session is upMore allocations, so more fragmentation; the peak during the handshake stays
CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA, ..._FREE_CA_CERTFrees the configuration and the CA certificate after the handshakeThe connection cannot renegotiate or reconnect without setting them up again
CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN with a smaller SSL_IN_CONTENT_LENShrinks the incoming buffer below 16 KBOnly safe when you control the server and it sends small records. A record larger than the buffer ends the connection
The certificate bundle with a short listFlash, mostly: the full bundle is largeYou must know which authorities your server will ever use

What that gets you, measured

The same application on an ESP32-S2 with ESP-IDF 5.5.3, holding one WebSocket over TLS open, with CONFIG_MBEDTLS_DYNAMIC_BUFFER on:

Bytes
Heap in use while connected and idle23,632
Further dip while data flowsabout 6,000
Flash added by TLSabout 155,000

So about 24 KB idle and 30 KB under traffic, measured as the free heap of the same firmware built with and without the connection. That is the cost after tuning, not before.

Things that do not help as much as they sound

When the device talks to one server only

Most of what TLS carries is there so that any client can talk to any server. A device with one server compiled into it needs less: proof that it reached that server, and encryption. The Noise protocol gives both with one known public key, no certificates and no 16 KB buffer.

Pinscope's device component was moved from TLS to Noise for this reason. The same application then needed 9,584 bytes in total, with every buffer fixed, instead of 23,632. The full account, with what the choice costs.

That is not an argument against TLS in your own firmware: if you call an HTTPS API you do not run, you need TLS, and the options above are how to make it fit.

Try it

Three devices are free with every feature, and no card is needed. Create an account, or read the five-minute guide first.

More