Basics
TLS cipher suites explained: names, AEAD and safe choices
A cipher suite is the named set of algorithms a TLS connection uses. A TLS 1.2 name lists the key exchange, authentication, bulk cipher and hash; a TLS 1.3 name lists only the AEAD cipher and key-derivation hash, and there are five. As of November 2026, enable the TLS 1.3 defaults plus TLS 1.2 ECDHE suites with AES-GCM or ChaCha20-Poly1305.
Anatomy of a TLS 1.2 cipher suite name
A TLS 1.2 suite name is a sentence with four slots, and reading it tells you exactly what the connection will do.
TLS _ ECDHE _ RSA _ WITH _ AES_128_GCM _ SHA256
| | | |
| | | +-- hash for the PRF (and the HMAC in CBC suites)
| | +---------------- bulk cipher, key size and mode
| +----------------------------- authentication: the certificate's key type
+------------------------------------- key exchange
| Slot | Common values | What it decides |
|---|---|---|
| Key exchange | ECDHE, DHE, RSA |
How the shared secret is created; only ephemeral (EC)DHE gives forward secrecy |
| Authentication | RSA, ECDSA |
Which certificate key type can be used |
| Bulk cipher | AES_128_GCM, AES_256_GCM, CHACHA20_POLY1305, AES_128_CBC, 3DES_EDE_CBC |
How records are encrypted |
| Hash | SHA256, SHA384, SHA (SHA-1) |
The TLS PRF; in CBC suites also the record MAC |
When the key exchange and authentication are the same algorithm, the name collapses: TLS_RSA_WITH_AES_128_CBC_SHA means RSA key transport and RSA authentication, with no ephemeral key at all.
OpenSSL uses its own shorter names. openssl ciphers -stdname prints both:
openssl ciphers -stdname 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA:AES128-SHA'
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - ECDHE-RSA-AES128-SHA TLSv1 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA1
TLS_RSA_WITH_AES_128_CBC_SHA - AES128-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA1
(The three TLS 1.3 lines OpenSSL always prints first are omitted here.) The TLSv1 and SSLv3 columns show the oldest protocol version a suite exists in, which is a quick hint that it is a legacy suite.
TLS 1.3: five suites and nothing else
TLS 1.3 removed key exchange and authentication from the suite name. Key exchange is negotiated through supported_groups and key_share, signatures through signature_algorithms, and the cipher suite only picks the AEAD and the HKDF hash.
| Code | Name | Status in RFC 9846 (same as RFC 8446) | Enabled by default in OpenSSL 3.x |
|---|---|---|---|
| 0x1301 | TLS_AES_128_GCM_SHA256 |
Mandatory to implement | Yes |
| 0x1302 | TLS_AES_256_GCM_SHA384 |
Should implement | Yes |
| 0x1303 | TLS_CHACHA20_POLY1305_SHA256 |
Should implement | Yes |
| 0x1304 | TLS_AES_128_CCM_SHA256 |
Optional | No |
| 0x1305 | TLS_AES_128_CCM_8_SHA256 |
Optional, short 8-byte tag | No |
This change ended the combinatorial explosion of TLS 1.2, where the IANA registry accumulated hundreds of code points for every combination of exchange, signature, cipher and hash. It also means a TLS 1.3 suite name tells you nothing about whether the key exchange was X25519, P-256 or the hybrid X25519MLKEM768; tools report the group separately, for example Negotiated TLS1.3 group: X25519MLKEM768 in openssl s_client -brief.
The July 2026 revision of TLS 1.3, RFC 9846, keeps the version number 0x0304 and the same five suites. Among its clarifications, it describes the key exchange in more generic language than the original RFC 8446, so that KEM-based key exchange such as ML-KEM fits the specification.
The two CCM suites exist for constrained devices. QUIC (RFC 9001) forbids TLS_AES_128_CCM_8_SHA256 because its 8-byte tag is too short for general use.
How a suite gets negotiated
The client proposes and the server decides. The ClientHello carries the client's full list of suites in preference order; the server picks one it also supports and names it in ServerHello. If there is no overlap, the server sends a handshake_failure alert.
In TLS 1.2 that single choice drags other constraints along:
- An
ECDHE_ECDSAsuite can only be picked if the server has an ECDSA certificate, and anECDHE_RSAsuite needs an RSA certificate. - The ECDHE curve comes from the client's
supported_groupsextension, so a suite can be acceptable while no common curve exists. - The signature over the ServerKeyExchange must use a hash the client listed in
signature_algorithms.
In TLS 1.3 these three decisions are independent. The server picks an AEAD suite, a group from key_share (or asks for another one with HelloRetryRequest), and a signature scheme that matches its certificate, each from its own list. That is why adding a post-quantum group or an Ed25519 certificate does not require new cipher suites.
On the client side you often cannot edit the list directly. Browsers ship fixed lists that change with releases. Java reads jdk.tls.disabledAlgorithms from its java.security file, Windows Schannel takes its order from Group Policy or PowerShell (Get-TlsCipherSuite), and curl or Python inherit the defaults of the TLS library they are linked against. When an internal client fails against a hardened server, check which library and version it uses before touching the server.
AEAD: why every modern suite uses it
AEAD (Authenticated Encryption with Associated Data) encrypts and authenticates in a single primitive, and TLS 1.3 allows nothing else. The three AEADs you will see are AES-GCM, ChaCha20-Poly1305 (RFC 7905) and AES-CCM.
Older TLS used CBC mode with a separate HMAC in a "MAC-then-encrypt" order. That construction leaked information through padding checks and timing, producing a decade of attacks: BEAST (2011) against TLS 1.0's predictable IVs, Lucky Thirteen (2013) timing attacks on CBC padding, and POODLE (2014) against SSL 3.0. AEAD modes have no padding oracle to attack. ChaCha20-Poly1305 is also fast in pure software, which is why phones and small ARM devices without AES instructions prefer it. See AEAD.
Forward secrecy and the key exchange slot
Only suites whose key exchange starts with ECDHE or DHE provide forward secrecy. With the static RSA key exchange, the client encrypts the pre-master secret to the server's certificate key, so anyone who later obtains that private key can decrypt every recorded session.
| Key exchange | Forward secrecy | Status |
|---|---|---|
RSA (key transport) |
No | Remove; also exposed to padding-oracle attacks such as ROBOT (2017) |
DHE (finite field) |
Yes | Slow and only safe with 2048-bit+ groups; dropped from Mozilla's 6.0 recommendations |
ECDHE |
Yes | Recommended for TLS 1.2 |
| TLS 1.3 (EC)DHE / hybrid | Yes | Always used, except pure-PSK resumption |
One caveat: session tickets are encrypted with a server-side ticket key. If that key lives for months and leaks, resumed sessions can be decrypted. Rotate ticket keys regularly or disable tickets on servers where you cannot.
What to disable and why
Anything without AEAD, without forward secrecy, or with a broken primitive should be off. The table lists what you still find on legacy servers:
| Family | Example (OpenSSL name) | Problem |
|---|---|---|
| NULL | NULL-SHA256 |
No encryption at all |
| Anonymous | ADH-AES128-SHA |
No authentication; trivial man-in-the-middle |
| Export | EXP-RC4-MD5 |
Deliberately weakened 40/56-bit keys; FREAK and Logjam (2015) |
| RC4 | RC4-SHA |
Statistical biases; prohibited by RFC 7465 (2015) |
| DES / 3DES | DES-CBC3-SHA |
64-bit blocks; Sweet32 (2016) finds collisions after about 2^32 blocks (32 GB) |
| CBC with SHA-1 | ECDHE-RSA-AES128-SHA |
MAC-then-encrypt padding and timing issues |
| Static RSA | AES128-GCM-SHA256 |
No forward secrecy |
| CCM_8 | TLS_AES_128_CCM_8_SHA256 |
Short tag; not for general web use |
Modern OpenSSL builds already exclude the worst of these. With OpenSSL 3.6, openssl ciphers -v 'RC4' and openssl ciphers -v '3DES' both return "no cipher match". RFC 9325 (BCP 195, November 2022) lists the suites the IETF currently recommends for TLS 1.2, which match the ECDHE plus AEAD list below.
Recommended configuration
For a public server, follow Mozilla's intermediate profile: TLS 1.2 and 1.3, with six ECDHE suites for TLS 1.2. Mozilla's guidelines are the de facto reference, and version 6.0, current as of November 2026, defines two profiles:
- Modern: TLS 1.3 only, with
TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384andTLS_CHACHA20_POLY1305_SHA256. Oldest compatible clients include Firefox 63, Chrome 70, Safari 12.1, Android 10 and Java 11. - Intermediate: TLS 1.2 and 1.3. For TLS 1.2 it allows exactly six suites:
ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-CHACHA20-POLY1305andECDHE-RSA-CHACHA20-POLY1305. Groups areX25519MLKEM768,X25519,prime256v1andsecp384r1, andserver_preferred_orderis false.
Compared with version 5.7, 6.0 dropped the three DHE suites and added the post-quantum hybrid group. An nginx server block following the intermediate profile:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
# X25519MLKEM768 needs nginx linked against OpenSSL 3.5 or later
ssl_ecdh_curve X25519MLKEM768:X25519:prime256v1:secp384r1;
ssl_ciphers only affects TLS 1.2 and below. TLS 1.3 suites come from OpenSSL's defaults, which are already the right three; to change them, nginx 1.19.4 and later accept ssl_conf_command Ciphersuites .... If nginx is linked against an OpenSSL older than 3.5, drop X25519MLKEM768 from the curve list or nginx will refuse to start.
The Apache equivalent uses the protocol prefix for TLS 1.3:
SSLProtocol -all +TLSv1.2 +TLSv1.3
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305
SSLCipherSuite TLSv1.3 TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
SSLHonorCipherOrder off
Notice that every TLS 1.2 suite appears twice, once for ECDSA and once for RSA certificates. A server can hold both certificate types and serve each client the one it supports. The TLS config generator produces these snippets for other servers.
Inspecting and testing suites with OpenSSL
openssl ciphers -v expands a cipher string into the exact suites it selects, so you can review a config before deploying it:
openssl ciphers -v 'ECDHE+AESGCM:ECDHE+CHACHA20' | grep TLSv1.2
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
ECDHE-RSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH Au=RSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
To check what a live server accepts, force one suite at a time with s_client: -cipher for TLS 1.2 and below, -ciphersuites for TLS 1.3.
# Does the server still accept a CBC suite over TLS 1.2?
openssl s_client -connect example.com:443 -tls1_2 -cipher ECDHE-RSA-AES128-SHA </dev/null
# Does it accept ChaCha20 over TLS 1.3?
openssl s_client -connect example.com:443 -tls1_3 -ciphersuites TLS_CHACHA20_POLY1305_SHA256 </dev/null
A handshake failure alert means the suite is disabled. The cipher and protocol cookbook has a loop that tests every suite, and the cipher suite lookup decodes any IANA or OpenSSL name.
Preference order and performance
With only strong suites enabled, order matters for performance rather than security. Clients list suites in their own preference; browsers on phones without AES acceleration put ChaCha20-Poly1305 first. If the server enforces its own order with AES-GCM first, those devices lose the faster cipher, which is why Mozilla now recommends letting the client choose. OpenSSL also has a PrioritizeChaCha option that keeps the server's order but honors a client that lists ChaCha20 first.
If a client and server share no suite at all, the handshake fails, and Chrome shows ERR_SSL_VERSION_OR_CIPHER_MISMATCH. That usually means a server restricted to TLS 1.3 or exotic suites met an old client, or a legacy client only speaking 3DES or RC4 met a modern server. Fix the server list instead of re-enabling broken suites when you can.
FAQ
Which cipher suites should I enable in 2026?
For most public sites: TLS 1.3 with its default suites, plus TLS 1.2 limited to ECDHE key exchange with AES-GCM or ChaCha20-Poly1305. That is Mozilla's "intermediate" profile (guidelines 6.0). If every client supports TLS 1.3, the "modern" profile (TLS 1.3 only) is simpler.
Is AES-256 safer than AES-128 for TLS?
Both are considered secure as of November 2026. AES-128-GCM is slightly faster and is the one TLS 1.3 makes mandatory to implement. AES-256 gives extra margin, including against future quantum attacks on symmetric keys, so many servers offer both and let clients choose.
Why does openssl ciphers show TLS 1.3 suites I did not ask for?
OpenSSL configures TLS 1.3 suites separately (the -ciphersuites option or the Ciphersuites setting), and openssl ciphers always appends them to the list it prints. Use -tls1_2 or check only the TLSv1.2 lines when reviewing a cipher string.
Should the server or the client choose the cipher order?
With a list that contains only strong AEAD suites, letting the client choose is fine and helps phones pick ChaCha20-Poly1305 when they lack AES hardware. Mozilla's 6.0 guidelines set server_preferred_order to false, which in nginx is ssl_prefer_server_ciphers off.
Sources
- RFC 9846: TLS 1.3 (July 2026), section 9.1 and appendix B.4
- RFC 9325: Recommendations for Secure Use of TLS and DTLS (BCP 195)
- RFC 7465: Prohibiting RC4 Cipher Suites
- RFC 7905: ChaCha20-Poly1305 Cipher Suites for TLS
- Mozilla wiki: Security/Server Side TLS
- Mozilla SSL Configuration Generator
- IANA: TLS Cipher Suites registry
- OpenSSL documentation: openssl-ciphers