Protocol
TLS 1.3: what changed from TLS 1.2 and how to enable it
TLS 1.3 is the current version of Transport Layer Security, first published as RFC 8446 in August 2018 and now specified by RFC 9846 (July 2026). It needs one round trip instead of two for a new connection, encrypts most of the handshake and drops every legacy algorithm behind past attacks. Run it alongside hardened TLS 1.2 for older clients.
What changed from TLS 1.2
TLS 1.3 is a redesign rather than an incremental update: it removes more than it adds.
| Area | TLS 1.2 (RFC 5246, now obsoleted by RFC 9846) | TLS 1.3 (RFC 9846, originally RFC 8446) |
|---|---|---|
| Full handshake | 2 round trips | 1 round trip |
| Resumption | Session IDs or tickets, 1 RTT | PSK tickets, optional 0-RTT data |
| Key exchange | Static RSA, DHE, ECDHE | Ephemeral (EC)DHE or hybrid only, or PSK with (EC)DHE |
| Forward secrecy | Only with (EC)DHE suites | Always for full handshakes |
| Ciphers | CBC, RC4, 3DES, GCM, ChaCha20... | AEAD only: AES-GCM, ChaCha20-Poly1305, AES-CCM |
| Cipher suites | Hundreds of combinations | Five |
| DH groups | Server can send arbitrary parameters | Named groups only (X25519, P-256, FFDHE from RFC 7919...) |
| Handshake signatures | RSA PKCS#1 v1.5, SHA-1 and MD5 allowed | RSA-PSS, ECDSA, EdDSA; PKCS#1 v1.5 only for legacy client keys (RFC 9963); no SHA-1 or MD5 |
| Certificate | Sent in clear | Encrypted |
| Compression | Supported (CRIME, 2012) | Removed |
| Renegotiation | Supported | Removed; replaced by KeyUpdate and post-handshake auth |
| ChangeCipherSpec | Real protocol message | Removed (dummy kept for middleboxes) |
| Key derivation | Custom PRF | HKDF with a structured key schedule |
The removed features were not decoration. Static RSA key exchange enabled Bleichenbacher-style attacks such as ROBOT (2017) and gave no forward secrecy. CBC padding enabled Lucky Thirteen; compression enabled CRIME; renegotiation needed an emergency fix in 2009; arbitrary DH parameters enabled Logjam. Each removal closed a class of bugs rather than one bug.
In July 2026 the IETF republished TLS 1.3 as RFC 9846. It is a minor, backward-compatible revision with the same version number: it clarifies text that was found unclear, forbids reusing key shares between connections, forbids negotiating TLS 1.0 and 1.1, limits the number of KeyUpdate messages, adds a general_error alert, and replaces the term "master" secret with "main". It also obsoletes RFC 5246, so the requirements for TLS 1.2 implementations now sit in the same document.
Faster: 1-RTT and 0-RTT
TLS 1.3 saves a round trip by having the client guess. The ClientHello already contains key shares for the groups the client expects the server to accept, so the server can compute keys and send its certificate, signature and Finished in its first reply. The client can send an HTTP request right after its own Finished, one round trip after it started.
TLS 1.2 full handshake TLS 1.3 full handshake
C: ClientHello ---> C: ClientHello + key_share --->
S: ServerHello, Certificate, S: ServerHello + key_share,
ServerKeyExchange, {EncryptedExtensions,
ServerHelloDone <--- Certificate, CertificateVerify,
C: ClientKeyExchange, Finished} <---
ChangeCipherSpec, Finished ---> C: {Finished} + [GET /] --->
S: ChangeCipherSpec, Finished <--- S: [200 OK] <---
C: [GET /] --->
S: [200 OK] <---
= 2 RTT before the request = 1 RTT before the request
If the guess is wrong the server sends a HelloRetryRequest and the handshake costs two round trips, still no worse than TLS 1.2. Message-level details are in the TLS 1.3 handshake.
Resumed connections can go further with 0-RTT: using a pre-shared key from an earlier session ticket, the client sends application data in its very first flight. The cost is security. Early data has no protection against replay, because the server cannot prove the data is fresh, and it is not forward secret with respect to the ticket key. The TLS 1.3 specification requires applications to opt in explicitly, and RFC 8470 defines the HTTP rules: the Early-Data: 1 header and the 425 Too Early status code. Most servers keep 0-RTT off by default; nginx's ssl_early_data directive defaults to off. See 0-RTT.
More private: an encrypted handshake
In TLS 1.3 everything after ServerHello is encrypted, including the server's certificate chain. A passive observer of a TLS 1.2 connection could read the certificate, and therefore every hostname in its SAN list, straight from the wire; with TLS 1.3 it sees only ClientHello and ServerHello.
The remaining leak is the hostname in the SNI extension of the ClientHello, which the server needs before it can pick a certificate. Encrypted Client Hello (ECH, standardized as RFC 9849 in March 2026) closes that gap: the client fetches the server's ECH public key from the HTTPS DNS record and encrypts the real ClientHello inside an outer one that names a shared front-end. ECH exists only for TLS 1.3, which is one more reason to enable it.
Downgrade protection
An attacker who can make both sides believe the other only supports TLS 1.2 could steer them into weaker crypto. TLS 1.3 defends against this in two layers.
First, the real version is negotiated in the supported_versions extension, and the whole handshake is authenticated by the Finished messages and the server's signature. Second, when a TLS 1.3-capable server ends up negotiating an older version, it writes a sentinel into the last eight bytes of its ServerHello random:
TLS 1.2 negotiated by a 1.3 server: 44 4F 57 4E 47 52 44 01 ("DOWNGRD" 01)
TLS 1.1 or lower: 44 4F 57 4E 47 52 44 00 ("DOWNGRD" 00)
The server random is covered by the server's signature, so an attacker cannot remove the sentinel, and a TLS 1.3 client that sees it aborts the connection. This replaces the older TLS_FALLBACK_SCSV mechanism (RFC 7507), which only protected against browsers retrying with lower versions.
Middlebox compatibility mode
A TLS 1.3 handshake is deliberately disguised as a TLS 1.2 session resumption. During standardization, field tests found that a noticeable share of firewalls, proxies and inspection boxes dropped connections that did not look like TLS 1.2, so the final design includes several pieces of camouflage:
ClientHello.legacy_versionis always0x0303(TLS 1.2); the real version list is insupported_versions.- The record layer header also says
0x0303, and encrypted records always use the outer typeapplication_data. - The client sends a random 32-byte
legacy_session_id, which the server echoes. - Both sides send a meaningless
ChangeCipherSpecrecord.
That is why a packet capture of a TLS 1.3 connection shows "TLS 1.2" record headers and ChangeCipherSpec messages. In openssl s_client -msg output you will see lines such as <<< TLS 1.2, RecordHeader followed by <<< TLS 1.3, ChangeCipherSpec; that is expected.
TLS 1.3 is where post-quantum key exchange lives
New key exchange methods are added to TLS 1.3 as named groups, without touching cipher suites. The most important is X25519MLKEM768 (code point 0x11EC), a hybrid of X25519 and the NIST-standardized ML-KEM-768, standardized in RFC 10024 (August 2026) together with SecP256r1MLKEM768 and SecP384r1MLKEM1024. Chrome enabled it by default in Chrome 131 in November 2024, and OpenSSL 3.5, released in April 2025, includes it in its default key shares. These hybrids are defined only for TLS 1.3, so a server still stuck on TLS 1.2 cannot offer quantum-resistant key exchange at all. Details in post-quantum TLS.
What stays the same
Your certificates, private keys and chains do not change when you enable TLS 1.3. The same RSA or ECDSA certificate serves TLS 1.2 and TLS 1.3 clients side by side, OCSP stapling and Signed Certificate Timestamps still work (they now travel as extensions on the Certificate entry), and HTTP-level settings such as HSTS are unaffected. ALPN still selects h2 or http/1.1, so HTTP/2 keeps working without changes.
One subtle difference concerns RSA keys. A TLS 1.3 server with an RSA key must sign the handshake with RSA-PSS, even when the certificate itself is signed with PKCS#1 v1.5, and the original RFC 8446 required RSA-PSS from clients too. Software keys handle this transparently, but some older hardware security modules, smart cards and TPM-backed client keys can only produce PKCS#1 v1.5 signatures. RFC 9963 (April 2026) added rsa_pkcs1_*_legacy code points that a server can offer in CertificateRequest for exactly these client keys. Where client or server does not implement RFC 9963, such keys still work over TLS 1.2 and fail over TLS 1.3, which typically shows up as client-certificate logins breaking after an upgrade. ECDSA keys are not affected.
Session resumption also changes shape. TLS 1.2 session IDs and tickets are replaced by TLS 1.3 PSK tickets, so shared session caches between servers behind a load balancer need their ticket keys synchronized as before, but old session-ID caches no longer help TLS 1.3 clients.
Who supports TLS 1.3
Support is universal on current software; problems come from old installations.
| Software | First version with TLS 1.3 (final RFC) |
|---|---|
| OpenSSL | 1.1.1 (September 2018) |
| Chrome | 70 |
| Firefox | 63 |
| Safari | 12.1 |
| Android | 10 |
| Java | 11 (backported to 8u261) |
| Windows (Schannel) | Windows 11 and Windows Server 2022 |
| Apache httpd | 2.4.36, with OpenSSL 1.1.1 |
| nginx | 1.13.0, with OpenSSL 1.1.1 |
The weak spots are servers whose TLS library predates 2018. CentOS 7 and RHEL 7 ship OpenSSL 1.0.2, and Windows Server 2019 and earlier have no TLS 1.3 in Schannel. Software that bundles its own TLS library, such as Java or Go, is independent of the system OpenSSL.
How to enable TLS 1.3
On a modern stack, enabling TLS 1.3 is a single word in the protocol list.
# nginx (built with OpenSSL 1.1.1 or later)
ssl_protocols TLSv1.2 TLSv1.3;
# Apache httpd 2.4.36+ with OpenSSL 1.1.1+
SSLProtocol -all +TLSv1.2 +TLSv1.3
Check the library version first: nginx -V 2>&1 | grep -i openssl shows what nginx was built with, and httpd -V or apachectl -M helps for Apache. Then verify from outside:
openssl s_client -connect example.com:443 -servername example.com -tls1_3 -brief </dev/null
curl -sv --tlsv1.3 -o /dev/null https://example.com/ 2>&1 | grep -E 'SSL connection|TLSv1.3'
If the server cannot speak TLS 1.3, s_client fails with a protocol version alert. The SSL checker reports the supported versions, and the cipher and protocol cookbook has commands to test each version.
Common deployment problems
Most TLS 1.3 issues come from layers around the web server rather than the protocol.
- The edge is not your server. If a CDN, cloud load balancer or WAF terminates TLS, its TLS policy decides the protocol. Your origin's nginx config does not matter to visitors.
- TLS 1.3-only breaks old clients. Mozilla's "modern" profile lists Firefox 63, Chrome 70, Safari 12.1, Android 10 and Java 11 as the oldest supported clients. Old Android phones, legacy Java apps and embedded devices fail with ERR_SSL_VERSION_OR_CIPHER_MISMATCH or a generic protocol error.
- Client certificates per URL. TLS 1.2 servers often requested a client certificate through renegotiation only for some paths. TLS 1.3 has no renegotiation, post-handshake authentication is not allowed with HTTP/2 (RFC 8740), and not every client implements it. Request client certificates for the whole host instead; see mutual TLS.
- 0-RTT replay. Turning on early data without application checks can let replayed requests through.
- TLS inspection boxes. Old intercepting proxies may fail on TLS 1.3 or on the larger post-quantum ClientHello. Updating the box is the real fix.
TLS 1.0 and 1.1 should already be off: RFC 8996 deprecated both in March 2021, RFC 9846 now forbids negotiating them, and browsers removed them around 2020. A configuration of TLS 1.2 and 1.3 with the suites in cipher suites is the safe default as of November 2026.
FAQ
Should I disable TLS 1.2 now that TLS 1.3 exists?
Not on most public sites. As of November 2026 Mozilla's intermediate profile still keeps TLS 1.2 (with ECDHE and AEAD suites only) for older clients, embedded devices and some enterprise software. TLS 1.3-only is reasonable for APIs and internal services whose clients you control.
Is 0-RTT safe to enable?
Only for requests that are safe to replay. An attacker who captures 0-RTT data can resend it, so a non-idempotent request such as a payment POST could execute twice. nginx keeps ssl_early_data off by default; if you enable it, pass the $ssl_early_data variable to the application and reject unsafe requests with 425 Too Early (RFC 8470).
Why does my TLS 1.3 server not offer TLS 1.3?
Usually because the web server is linked against an old TLS library (OpenSSL 1.0.2 has no TLS 1.3), the ssl_protocols line omits TLSv1.3, or a load balancer or CDN in front terminates TLS with its own settings. Run nginx -V to see the OpenSSL version and test the public endpoint with openssl s_client -tls1_3.
Does TLS 1.3 hide the domain name?
It encrypts the certificate, but the hostname is still sent in clear text in the SNI extension of the ClientHello. Encrypted Client Hello (ECH, RFC 9849), which builds on TLS 1.3, encrypts the SNI when the site publishes an ECH configuration in DNS.
Sources
- RFC 9846: The Transport Layer Security (TLS) Protocol Version 1.3 (July 2026)
- RFC 8446: TLS 1.3, original 2018 specification (obsoleted by RFC 9846)
- RFC 8996: Deprecating TLS 1.0 and TLS 1.1
- RFC 8470: Using Early Data in HTTP
- RFC 10024: Post-Quantum Traditional (PQ/T) Hybrid Key Agreement Mechanisms for TLS 1.3
- RFC 9849: TLS Encrypted Client Hello
- nginx: Module ngx_http_ssl_module
- Mozilla wiki: Security/Server Side TLS