← Knowledge base

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.

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 -T

sshd -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.