Check OpenSSH key exchange
SSH uses one algorithm to establish session keys and others to authenticate hosts and users. This guide checks the session's key exchange without running a remote command. Keep authentication readiness as a separate task.
Before you start
Use an approved OpenSSH client, the host/account you normally connect to, and a host key already verified through your normal trusted onboarding process. Do not replace a changed key or disable host-key checking just to complete the test. The example is POSIX shell syntax; Windows OpenSSH users can enter the options on one line.
OpenSSH documents hybrid defaults from 9.0, ML-KEM support from 9.9, and ML-KEM preference from 10.0. Vendor backports and policy can differ, so inspect actual capability and selection. OpenSSH's PQ guidance explains the algorithms and migration.
Validation scope: this procedure is documentation-reviewed. Output below is illustrative, not an assertion about a tested fleet or every vendor package.
1. Inspect capability and effective policy
ssh -V
ssh -Q kex
# Substitute your usual SSH host alias and account.
ssh -G [email protected]ssh -Q kex lists compiled-in capabilities. In the ssh -G output, find kexalgorithms, hostname, port, and any proxy/jump-host settings. It shows the effective configuration for that destination, not a handshake. Keep full output private if it identifies internal hosts or paths. See ssh's command reference.
Look for mlkem768x25519-sha256 or sntrup761x25519-sha512 (some releases use the @openssh.com suffix for the latter). Capability is useful evidence for planning, but the server must support a compatible algorithm too.
2. Observe a fresh handshake
ssh -vv -N -T \
-o BatchMode=yes -o StrictHostKeyChecking=yes \
-o ConnectTimeout=10 -o ConnectionAttempts=1 \
-o ControlMaster=no -o ControlPath=none \
-o ClearAllForwardings=yes -o ForwardAgent=no -o ForwardX11=no \
-o RemoteCommand=none -o PreferredAuthentications=none \
[email protected]This uses your normal host configuration while disabling connection sharing, forwarded services, and remote commands. It requests no credential-based authentication; a permission-denied ending is expected on ordinary accounts. If the connection remains open, stop it with Ctrl+C after the handshake. The options are documented in ssh_config.
A jump host introduces a separate SSH connection. Match each debug line to the destination it describes, and assess the jump-host hop independently. Debug output may contain usernames, addresses, and key fingerprints; retain only needed evidence and redact before sharing.
3. Distinguish key exchange from authentication
Illustrative excerpt: omitted lines are shown as ellipses.
debug1: kex: algorithm: mlkem768x25519-sha256
...
debug1: Host 'ssh.example.com' is known and matches the ED25519 host key.
...
[email protected]: Permission denied (publickey).The selected kex: algorithm line records hybrid session-key establishment. The matching known-host line confirms the server identity check succeeded. The final authentication rejection does not undo the earlier handshake observation, but it does mean this was not a successful account login.
- ML-KEM/X25519 or sntrup761/X25519 selected: record that exact hybrid algorithm, verified host, client/server versions if known, and time.
- curve25519-sha256 or another classical KEX selected: inspect both endpoints' effective policy and supported software.
- No completed verified handshake: leave the result unknown. A host-key mismatch requires investigation before trusting any peer claim.
- ED25519, RSA, or ECDSA host key: this is authentication evidence, not the KEX result. Track signature migration separately.
4. Upgrade and retest safely
Upgrade through your OS/server vendor's supported stable packages. If both endpoints already support hybrid KEX, investigate old KexAlgorithms allowlists and configuration includes before adding more overrides. Restoring vendor defaults may be appropriate after compatibility review; do not paste a policy that removes recovery access.
# On a server you administer, using the actual deployed sshd binary:
sudo /usr/sbin/sshd -t
sudo /usr/sbin/sshd -Tsshd -t checks configuration and keys; -T prints effective settings. If the service uses a different binary/configuration, use those arguments. For per-user/address Match rules, use the documented -C connection specification. See sshd and server configuration.
Before changing SSH, preserve the previous configuration/package and keep an existing administrative session plus console recovery available. Validate, then reload through the platform's service manager. Open a second connection, repeat this check, and confirm a normal authorized login before closing the first session.
If the result is unexpected
An unsupported option points to the local client version. A no-matching-KEX error points to incompatible offered policies. A timeout can be routing, firewall, or the configured jump host. A classical result with a capable client often needs a server upgrade or policy review; silencing a warning does not change encryption.
If a staged change breaks access, restore the saved configuration/package using the retained session or console, validate again, and retest. Record the unresolved host and next owner in the readiness worksheet.
Documentation reviewed 25 September 2026. Consult the manuals shipped with your vendor's installed OpenSSH release.