ML-KEM has been the default SSH key exchange for two years. Enterprise IT just noticed.
Published by RodHat

The helpdesk tickets have been trickling in for months. Now they are a flood.
SSH connections from corporate jump boxes to anything running a current distro
are timing out on the key exchange, falling back slowly, sometimes failing
outright with no useful error. The root cause is OpenSSH 9.9, which shipped
in October 2024 and made mlkem768x25519-sha256 the default key exchange
algorithm.
Two years ago. The change happened two years ago.
What actually changed
The SSH protocol negotiates the key exchange algorithm during the initial
handshake. Client and server each advertise what they support, pick the highest
preference they share, and proceed. OpenSSH 9.9 put ML-KEM hybrid first on both
sides. A client running 9.9 or later connecting to a server running 9.9 or later
negotiates mlkem768x25519-sha256 and gets on with it.
The problem is one side being old. If your jump box is still on OpenSSH 8.x from
a corporate Ubuntu 20.04 image that nobody has touched since the LTS rollout, it
does not know what ML-KEM is. Negotiation falls back to the next mutually
supported algorithm, usually curve25519-sha256 or an ECDH variant. That is
fine. Fallback negotiation is working exactly as designed.
Except some sites hardcode their KexAlgorithms line to a specific list written
circa 2019. Some old versions of PuTTY, some corporate SSH gateway appliances,
some embedded SSH stacks in network hardware do not negotiate gracefully. They
send their preference list, the remote end offers mlkem768x25519-sha256 first,
and something in the parsing logic on the old end breaks in a way that produces
no useful error. Connection drops. Helpdesk ticket opens.
Why ML-KEM is the correct default
The threat is called “harvest now, decrypt later.” Nation-state actors with sufficient storage capture encrypted sessions today and decrypt them once a capable enough quantum computer exists. RSA and ECDH are quantum-vulnerable. The ciphertext is safe for now, but “now” has an expiration date that is not zero. If you are operating SSH infrastructure in a context where adversaries are plausibly recording your traffic, that matters.
ML-KEM is NIST FIPS 203, standardized in August 2024: the Module-Lattice-based
Key Encapsulation Mechanism. OpenSSH uses a hybrid: mlkem768x25519-sha256
combines ML-KEM-768 with classical X25519. Both algorithms have to be broken
simultaneously to break the session key. If ML-KEM’s lattice assumptions turn
out to be wrong, X25519 holds. If a quantum computer eventually breaks X25519,
ML-KEM holds. You get post-quantum security without abandoning the classical
security proof.
NIST published FIPS 203. OpenSSH waited for the final standard before flipping the default. This is the correct sequence. The timeline was not rushed.
Finding the breakage
On a server, check your effective running configuration:
sshd -T | grep kex
If kexalgorithms does not include mlkem768x25519-sha256 near the front,
your sshd_config has an explicit KexAlgorithms line that predates 9.9. Drop
the line entirely and let the OpenSSH default take over. Removing an overly
specific KexAlgorithms line is almost always the correct fix.
On a client, check what your installed version actually supports:
ssh -Q kex
If mlkem768x25519-sha256 is absent, your SSH client is the compatibility
problem. Update it.
For diagnosing a specific failing connection:
ssh -vvv user@host 2>&1 | grep -E 'kex|KEX|algo'
The verbose output shows exactly what each side offered and where negotiation went sideways.
For situations where you cannot update the remote end immediately, force a specific algorithm on the client:
ssh -o KexAlgorithms=curve25519-sha256 user@host
This is a workaround, not a fix. Update the other end.
Who owns this
The OpenSSH project documented the change in the 9.9 release notes, ran a multi-version transition with support added well before it became the default, and updated on a schedule that is not aggressive by any reasonable measure. Major distros packaged it promptly.
Corporate environments running three-year-old SSH infrastructure without a patching process own this one entirely. The tickets hitting helpdesk right now are not evidence that OpenSSH got the transition wrong. They are a measurement of how far behind corporate patching culture has drifted relative to the actual threat model.
Update your SSH clients and servers. Drop hardcoded KexAlgorithms lines from
configs that predate 9.9. Run sshd -T | grep kex and confirm
mlkem768x25519-sha256 is in the list. This is not complicated. The complicated
part was the last twenty years of pretending harvest-now-decrypt-later was
somebody else’s problem.
See also: OpenSSL 3.0 EOL and what it means for your crypto stack for the adjacent conversation about keeping cryptographic libraries current, and seccomp-bpf syscall filtering for hardening the process boundary around the services your SSH sessions reach.
Sources
- OpenSSH 9.9 release notes (OpenSSH)
- FIPS 203: Module-Lattice-Based Key-Encapsulation Mechanism Standard (National Institute of Standards and Technology)