Articles › Security

Post-quantum SSH and HTTPS: what ML-KEM is and how to check your server

OpenSSH 10 defaults to mlkem768x25519 and 10.1 warns when it is not used; browsers offer X25519MLKEM768. How to see what your server negotiates, and what to upgrade.

Intermediate 6 min read October 23, 2026

What you will learn
  • OpenSSH 10.0 (April 2025) uses mlkem768x25519-sha256 by default, and 10.1 warns when a connection does not use a post-quantum key exchange
  • The hybrid combines ML-KEM with X25519, so if ML-KEM is ever broken it is still as strong as plain X25519
  • Check SSH with ssh -v and the kex algorithm line, and HTTPS with openssl s_client from OpenSSL 3.5 or later
  • Ubuntu 24.04 only gets sntrup761 for SSH and no PQ HTTPS from the system OpenSSL; you need Ubuntu 26.04 or Debian 13

“Post-quantum” sounds far away, but it has already reached your machines quietly. Since OpenSSH 10.0 (April 2025) SSH uses a hybrid ML-KEM plus X25519 key exchange by default, and OpenSSH 10.1 started printing a warning when the server cannot do it. On the web, Chrome has offered X25519MLKEM768 on HTTPS connections since version 131. This article explains what it protects against, how to check your own servers, and what to upgrade.

Tested on: OpenSSH_9.7p1 (Windows), running ssh -Q kex and ssh -v for real. Ubuntu and Debian package versions checked on Launchpad and packages.debian.org, and OpenSSH details on openssh.org, as of October 2026 (the latest release is 10.6, from 6 October 2026).

The threat: store now, decrypt later

The key exchange is the step where both sides agree on a session secret that an eavesdropper cannot learn. Today’s methods (X25519, ECDH) are safe against normal computers, but the maths underneath can be solved by a large enough quantum computer.

No such machine exists yet. OpenSSH’s post-quantum page describes the threat that exists today: someone records encrypted traffic now and decrypts it once the machine arrives, called store now, decrypt later. Anything sent over SSH or HTTPS today is exposed from today unless the key exchange is post-quantum.

What does not need to change urgently is signatures and authentication keys (host keys, user keys, TLS certificates). Impersonation has to happen during the connection and cannot be done after the fact, so ed25519 keys are fine.

ML-KEM + X25519quantum-resistantX25519 still holds~2.3 KB per connectionX25519 onlysafe todaybreakable by quantumrecord now, decrypt later
A hybrid is never weaker than what it replaces

ML-KEM, and why hybrid

ML-KEM is NIST’s quantum-resistant key encapsulation standard (FIPS 203, derived from Kyber). The name mlkem768x25519 says it uses both ML-KEM-768 and X25519 and combines the results into one key.

OpenSSH’s pq.html gives the reason: a hybrid is guaranteed to be no worse than what we had. If ML-KEM turns out to have a flaw, X25519 still holds; if a quantum computer breaks X25519, ML-KEM still holds.

NameUsed inDefault since
sntrup761x25519-sha512@openssh.comSSHOpenSSH 9.0 (April 2022)
mlkem768x25519-sha256SSHadded in 9.9, default in 10.0 (April 2025)
X25519MLKEM768TLS 1.3 / HTTPSChrome 131, OpenSSL 3.5 (April 2025)

On the TLS side X25519MLKEM768 is now standardised in RFC 10024, with codepoint 0x11EC.

Worked example: how much extra data

ML-KEM-768 sizes: public key 1,184 bytes, ciphertext 1,088 bytes. X25519 uses 32 bytes per side.

  1. Client sends: 1,184 + 32 = 1,216 bytes (matching the client share size in RFC 10024)
  2. Server replies: 1,088 + 32 = 1,120 bytes
  3. Both directions: 1,216 + 1,120 = 2,336 bytes ≈ 2.3 KB
  4. Compared with X25519 alone: 32 + 32 = 64 bytes, so about 2.27 KB more per connection

You pay it once at the start of a session. After that everything is encrypted with the same ciphers as before (chacha20-poly1305 or AES-GCM, for example) at no extra cost.

Check SSH: what is actually negotiated

# What your client supports
ssh -Q kex | grep -E 'mlkem|sntrup'

# Connect and see what was agreed
ssh -v user@server.example.com exit 2>&1 | grep 'kex: algorithm'

Output on our test machine (a 9.7 client, which has no mlkem yet) connecting to github.com:

debug1: kex: algorithm: sntrup761x25519-sha512@openssh.com

mlkem768x25519-sha256 or sntrup761x25519-sha512@openssh.com means post-quantum. curve25519-sha256 or ecdh-sha2-nistp256 means not.

On the server, see the effective setting after all config files are merged:

sudo sshd -T | grep -i kexalgorithms

If you only see curve25519 and diffie-hellman entries, find who set KexAlgorithms in /etc/ssh/sshd_config or /etc/ssh/sshd_config.d/. Older hardening guides often pin a fixed list, which silently drops post-quantum. pq.html itself says to check this first.

Modern OpenSSH defaults are better than a list you wrote yourself. Unless you have a specific reason, delete the KexAlgorithms line and let the defaults work.

For the rest of SSH hardening, such as disabling password logins, see securing SSH; the two do not conflict.

The warning in OpenSSH 10.1

With a 10.1 or newer client, connecting to a server without PQ support prints a message that starts:

** WARNING: connection is not using a post-quantum key exchange algorithm.

The right fix is to upgrade the server. For a device you cannot upgrade (an old router or NAS), silence it for that host only in ~/.ssh/config, as pq.html suggests. Don’t turn it off globally.

Match host old-nas.example.com
    WarnWeakCrypto no-pq-kex

Check HTTPS

Current Chrome already offers X25519MLKEM768, so it is down to the server. You need OpenSSL 3.5 or later both to check and to serve it.

# needs openssl 3.5+ on the machine running the command
echo | openssl s_client -connect example.com:443 -tls1_3 2>/dev/null \
  | grep 'Negotiated TLS1.3 group'

X25519MLKEM768 means the server supports it; no line, or X25519, means not yet. Alternatively open Chrome DevTools, Security tab, and look at the key exchange.

nginx defaults to ssl_ecdh_curve auto, which per the nginx docs means the list built into OpenSSL. So if nginx is linked against OpenSSL 3.5 and nobody overrides it, you should get PQ automatically. If your config has something like ssl_ecdh_curve secp384r1; from an old guide, remove it or put X25519MLKEM768 first, then check again with the command above.

Which system gets what

SystemOpenSSHOpenSSLSSH PQHTTPS PQ (system OpenSSL)
Ubuntu 22.048.93.0check itno
Ubuntu 24.049.63.0sntrup761no
Ubuntu 26.0410.23.5mlkem768yes
Debian 129.23.0sntrup761no
Debian 1310.03.5mlkem768yes

Versions from Launchpad and packages.debian.org, as of October 2026. The SSH PQ column is the default for that version (9.0+ gets sntrup761, 10.0+ gets mlkem768). Ubuntu 22.04 ships 8.9, older than 9.0 where PQ became the default, so run sshd -T and see.

Common mistakes

  • A pinned KexAlgorithms list from a 2020 guide. The machine is upgraded and still has no PQ.
  • Turning off WarnWeakCrypto everywhere because it is noisy, and never learning which hosts are still old.
  • Checking HTTPS with an old openssl. OpenSSL 3.0 does not know X25519MLKEM768 and will report no support even when the server has it.
  • Rushing to replace host keys or certificates. Not needed yet; the key exchange is what is urgent.
  • Forgetting what sits in front. If TLS terminates at a CDN or load balancer, that is what users negotiate with, not your nginx.

Sources

FAQ

Quantum computers cannot break anything yet. Why hurry?

Because traffic recorded today can be decrypted on the day a large enough machine exists; this is called store now, decrypt later. Anything that must stay secret for years, such as passwords or customer data going over SSH today, is at risk from today, not from the day the quantum computer is finished.

Do I need post-quantum SSH keys too?

Not yet. What OpenSSH changed is the key exchange that creates each session's encryption keys, the part that can be recorded now and broken later. Host keys and user keys authenticate the connection at the moment it happens and cannot be forged retroactively, so keep using ed25519.

Does it slow things down?

Not noticeably. The extra data is about 2.3 KB of key shares per connection (worked out below). After that the session uses the same ciphers as before.

Commands and settings were tested on sample systems. Try them on a test machine before production.