SSD Nodes Learn Hosting plans →
Guides Matt ConnorBy Matt Connor · Updated 2026-09-23

Fix the SSH post-quantum key exchange warning

Your ssh client warns that the connection is not using a post-quantum key exchange. Find which algorithm you negotiate, and fix the right side.

What the post-quantum key exchange warning means

Your ssh client prints the post-quantum key exchange warning when the key exchange it negotiated with the server is not one of the hybrid post-quantum algorithms OpenSSH supports. The session is still encrypted. Nothing about it is broken today. The warning is about later: someone who records the encrypted traffic now could decrypt it in the future, once a quantum computer large enough to break X25519 exists.

OpenSSH calls that attack "store now, decrypt later". It only works on traffic that somebody kept a copy of. The fix is usually one configuration line on the server, so it is worth doing even though nothing is on fire.

KEX is short for key exchange, the step where the two ends agree on the symmetric keys that encrypt the rest of the session. It happens before you authenticate, so it protects your password and your key exchange alike. If the protocol itself is new to you, what SSH is and what the protocol actually does is the shorter read first, and what changed in OpenSSH when post-quantum key exchange became the default covers the background to this warning.

The exact warning, and which OpenSSH release prints it

** WARNING: connection is not using a post-quantum key exchange algorithm.
** This session may be vulnerable to "store now, decrypt later" attacks.
** The server may need to be upgraded. See https://openssh.com/pq.html

OpenSSH 10.1, released on 6 October 2025, added it. The release notes describe the change as "a warning when the connection negotiates a non-post quantum key agreement algorithm", controlled by a new WarnWeakCrypto option in ssh_config(5) that defaults to on.

Two facts follow, and both matter when you go looking for the cause. The warning comes from the client, ssh, and never from the server, sshd, so the person who runs the server never sees it. And it only appears when the client is OpenSSH 10.1 or newer. As of September 2026 Ubuntu 24.04 ships OpenSSH 9.6p1, which predates the warning entirely, so a 24.04 client stays quiet even when it negotiates a classical key exchange. Ubuntu 26.04 ships OpenSSH 10.2p1, which warns.

The third line, "The server may need to be upgraded", is the client's guess. It is often right. It is also wrong often enough to send people down the wrong path, because a fully current server whose KexAlgorithms line came from an old hardening guide produces exactly the same warning.

Which key exchange does your client actually offer?

Do not guess from a version number you half remember. Ask the binary.

ssh -V
ssh -Q kex

ssh -V prints the version, on stderr, in the form OpenSSH_10.2p1 Ubuntu-2ubuntu3.6, OpenSSL .... ssh -Q kex prints every key exchange name this build knows about. Read that list on your own machine rather than trusting one from a blog, because it changes between releases: mlkem768x25519-sha256 arrived in OpenSSH 9.9 (September 2024), so a 9.6 client on Ubuntu 24.04 cannot list it, while sntrup761x25519-sha512@openssh.com has been the default since OpenSSH 9.0 (April 2022) and is present there.

Only two families in that output are post-quantum. Filter for them:

ssh -Q kex | grep -E 'mlkem|sntrup'

If that prints nothing, this build has no post-quantum key exchange at all and no amount of configuration will add one. Upgrade the package. If it prints one or more names, the client is capable, and the problem is on the other side or in a config file.

Capability is not the same as what got chosen. To see the algorithm a real connection settled on, run this against a host you administer:

ssh -vv user@server.example.com 2>&1 | grep 'kex: algorithm'

The line reads debug1: kex: algorithm: mlkem768x25519-sha256 when the negotiation went well. Any other value on that line is the reason the warning appeared, because the client only warns about the algorithm it actually used. This step needs a reachable server, so run it from your own workstation.

Which key exchange algorithms does your server offer?

On the server itself, ask sshd for its effective configuration:

sudo sshd -T | grep -i '^kexalgorithms'

sshd -T is extended test mode. It parses the whole configuration, including every file pulled in by Include, and prints the values sshd will really use. Reading /etc/ssh/sshd_config by eye is unreliable, because Ubuntu puts Include /etc/ssh/sshd_config.d/*.conf at the top of that file, and for sshd the first value obtained for an option wins. A drop-in therefore beats anything written lower down, which is the opposite of what most people expect.

If the printed list holds no mlkem and no sntrup entry, you have found your cause. There are two ways to get there. The OpenSSH build is older than 9.9 and has nothing post-quantum to offer. Or a KexAlgorithms line somewhere removed them: hardening templates written before 2025 commonly pin a fixed list such as curve25519-sha256 plus diffie-hellman-group16-sha512, and a fixed list written then cannot contain an algorithm that did not exist yet. If you applied one while hardening SSH on your VPS, that line is where to look first.

Fix the server with a drop-in file

Leave /etc/ssh/sshd_config alone. Package upgrades prompt about modified config files, and a drop-in is easier to delete when it turns out to be wrong.

Build the list from what the server itself reports, so you cannot name an algorithm it does not have:

ssh -Q kex | grep -E 'mlkem|sntrup' | paste -sd,

Paste that output, followed by curve25519-sha256 as a fallback for older clients, into a new file:

sudo tee /etc/ssh/sshd_config.d/60-pq-kex.conf >/dev/null <<'EOF'
KexAlgorithms mlkem768x25519-sha256,sntrup761x25519-sha512@openssh.com,curve25519-sha256
EOF
sudo sshd -t

sshd -t is the check that saves you. It parses the configuration and exits without starting anything. A healthy result is no output at all and an exit status of 0. Every name in your KexAlgorithms line must exist in that server's ssh -Q kex output, so on an OpenSSH 9.6 server the mlkem768x25519-sha256 entry is rejected: sshd -t exits non-zero and prints a message naming the file, the line number and the algorithm string it did not recognise, with the phrase Bad SSH2 KexAlgorithms in it. Drop that name from the list and run sshd -t again.

Only once sshd -t is silent should you reload:

sudo sshd -t && sudo systemctl reload ssh

Keep your current SSH session open in another terminal while you do this, and open a second, fresh connection to confirm you can still log in. A reload does not disturb sessions that already exist, so a configuration that passes sshd -t but breaks negotiation will only show up on the next login, which is exactly when you want a working session still in hand. Ubuntu 24.04 and 26.04 can run sshd from a systemd socket unit instead of a long-running daemon. If systemctl reload ssh reports that the unit is not running, check systemctl status ssh.socket: under socket activation a fresh sshd reads the configuration on every new connection, so the change is already live.

Then reconnect and check the negotiated algorithm with the ssh -vv command above. The warning should be gone.

Fix the client, and how to silence the warning honestly

A client older than 10.1 never prints this warning, so upgrading your client can make a warning appear on a connection that was always classical. That is the tool getting better, not the connection getting worse.

You can see the client configuration that would apply to a host without connecting to it:

ssh -G server.example.com | grep -iE 'kexalgorithms|warnweakcrypto'

ssh -G prints the effective client options after every Include and Host block is resolved. If warnweakcrypto is missing from the output, your client predates OpenSSH 10.1, which is a more reliable version check than reading a package name.

When the far end genuinely cannot be fixed, turn the warning off for that host alone in ~/.ssh/config:

Host legacy-switch.example.net
    WarnWeakCrypto no

Newer OpenSSH releases accept a narrower value, WarnWeakCrypto no-pq-kex, which suppresses only the post-quantum warning and keeps any future weak-crypto warnings switched on. That flag arrived after 10.1, so run man ssh_config on your own machine and look at the WarnWeakCrypto entry before you use it. If your build only documents yes and no, use no.

Do not put WarnWeakCrypto no under Host *. That turns off the warning for every server you will ever connect to, including the ones you could have fixed in a minute, and you will not notice when a working server regresses.

The matching client-side change, forcing post-quantum only, deserves a caution. Setting KexAlgorithms mlkem768x25519-sha256 under Host * does not upgrade old servers. It makes connections to them fail outright with Unable to negotiate with 203.0.113.10 port 22: no matching key exchange method found, followed by the server's offer. That is a deliberate choice for a fleet you control, and a bad surprise everywhere else.

What a post-quantum key exchange does not protect

Be precise about what you just bought. A post-quantum key exchange protects the confidentiality of traffic that an attacker records today and tries to decrypt years from now. That is the whole of it.

It does nothing about a server someone already has a shell on. It does nothing about a private key copied off a laptop, a stale entry left in authorized_keys, or a password nobody rotated. Those are the ways servers actually get taken, and they are where generating, storing and retiring SSH keys properly earns far more than a key exchange upgrade does.

It also does not make authentication quantum-resistant. Host key and user key signatures still use classical algorithms such as ssh-ed25519 and rsa-sha2-512, and OpenSSH treats that as the less urgent half on purpose. Forging a signature is only useful at the moment the connection is made, so an attacker would need the quantum computer while you are logging in. Recorded ciphertext is different, because a copy keeps indefinitely and the attacker can come back to it whenever the hardware arrives.

Why a hybrid algorithm and not a pure post-quantum one

Both mlkem768x25519-sha256 and sntrup761x25519-sha512@openssh.com combine a post-quantum scheme with ordinary X25519 elliptic curve Diffie-Hellman, and the session key depends on both halves. If the post-quantum half is later broken by cryptanalysis, the connection is no weaker than plain curve25519-sha256, which is what almost everyone was using before. If X25519 falls to a quantum computer, the post-quantum half still holds. You do not have to bet on either one.

When the other end cannot do post-quantum at all

This is the case most readers hit next. A switch, a storage appliance, a build agent on an old distribution, or a router running Dropbear will never offer mlkem768x25519-sha256, and there is no configuration on your side that creates an algorithm the other end does not implement.

The honest options are these.

  1. Upgrade the far end. Best outcome, and often impossible on hardware whose vendor stopped shipping firmware.
  2. Narrow who can record the traffic. Reach the device over a management network or through a jump host you control, so the leg crossing the public internet is post-quantum. Say plainly what this does and does not do: it shrinks the set of people positioned to capture the session, and the inner leg is still classical.
  3. Accept it for that host and write the exception down. A per-Host WarnWeakCrypto line in ~/.ssh/config with a comment naming the device and the reason is a record you can audit later. A global switch-off is not.
  4. Rotate the secrets that crossed that link. Any credential typed over a classical session is the one at risk in a store-now-decrypt-later scenario, so changing it now puts the recorded copy out of date.

Option 4 is the one people skip, and it is the only one that helps with traffic already captured. The key exchange you fix today protects tomorrow's sessions. It cannot reach back.

FAQ

Why does ssh say the connection is not using a post-quantum key exchange algorithm?

Because the key exchange your client and server agreed on was a classical one such as curve25519-sha256, and OpenSSH 10.1 and newer warn about that. The session is encrypted normally. The risk the warning names is an attacker recording the traffic and decrypting it years later with a quantum computer. Find the negotiated algorithm with ssh -vv user@host 2>&1 | grep 'kex: algorithm', then check what the server offers with sudo sshd -T | grep -i '^kexalgorithms'.

Which OpenSSH version added the warning, and which algorithms count as post-quantum?

OpenSSH 10.1, released 6 October 2025, added the warning and the WarnWeakCrypto option that controls it. Two key exchanges count as post-quantum: sntrup761x25519-sha512@openssh.com, the default since OpenSSH 9.0 in April 2022, and mlkem768x25519-sha256, added in OpenSSH 9.9 in September 2024 and made the default in OpenSSH 10.0. Run ssh -Q kex | grep -E 'mlkem|sntrup' to see which of them your build supports.

My server is up to date and I still get the warning. What is wrong?

A KexAlgorithms line is overriding the defaults. Run sudo sshd -T | grep -i '^kexalgorithms' and compare it with ssh -Q kex on the same machine. If sshd reports a shorter list with no mlkem or sntrup entry, a hardening drop-in under /etc/ssh/sshd_config.d/ is pinning algorithms chosen before those existed. Ubuntu's Include sits at the top of sshd_config and sshd keeps the first value it obtains, so the drop-in wins over the main file.

Can I just turn the warning off?

Yes, per host, with WarnWeakCrypto no inside a Host block in ~/.ssh/config, and newer builds accept WarnWeakCrypto no-pq-kex to suppress only this one warning. Check the WarnWeakCrypto entry in man ssh_config on your machine to see which values your build accepts. Do not set it under Host *: you lose the signal on every server you could have fixed, and rotating the credentials used over that link is the step that actually reduces the risk.