Table of Contents

How to change SSH ciphers

Changing the SSH cipher list controls which encryption algorithms protect remote shells, SFTP transfers, and forwarded traffic. Adjusting that list is useful when older ciphers need to be removed, when a host should prefer a faster modern option, or when a server must match a security baseline.

OpenSSH negotiates one cipher in each direction during session setup. On current Ubuntu and Debian systems, the server-side Ciphers directive is usually set in /etc/ssh/sshd_config or a file under /etc/ssh/sshd_config.d, while clients can override their own preference in /etc/ssh/ssh_config or ~/.ssh/config. ssh -Q cipher shows the ciphers compiled into the local build, sshd -T shows the effective server policy, and ssh -G shows the effective client policy for a target host.

Examples below use the current Ubuntu and Debian package layout and a standard per-user OpenSSH client config. OpenSSH uses the first value it reads for most directives, so conflicting Ciphers lines in the main file and snippet files can quietly override later edits; test the daemon with sshd -t, keep another administrative path open, and confirm the negotiated cipher from a separate client before closing the working session.

Steps to change SSH ciphers on the server:

  1. Open a terminal on the SSH server with an account that can use sudo.
  2. List the ciphers supported by the installed OpenSSH build.
    $ ssh -Q cipher
    3des-cbc
    aes128-cbc
    aes192-cbc
    aes256-cbc
    aes128-ctr
    aes192-ctr
    aes256-ctr
    aes128-gcm@openssh.com
    aes256-gcm@openssh.com
    chacha20-poly1305@openssh.com

    ssh -Q cipher lists every cipher compiled into the client, including legacy CBC names that are not part of the current default server policy.

  3. Check the current cipher list that sshd will offer.
    $ sudo sshd -T | grep '^ciphers '
    ciphers chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com

    sshd -T expands included files and defaults, so it is the most direct way to confirm the active server policy before and after an edit.

  4. Check whether the main server config loads a snippet directory.
    $ grep -n '^Include' /etc/ssh/sshd_config
    12:Include /etc/ssh/sshd_config.d/*.conf

    On Ubuntu and Debian, a dedicated snippet file such as /etc/ssh/sshd_config.d/10-ciphers.conf is usually cleaner than editing the main file directly.

  5. Open the server config location that should carry the Ciphers directive.
    $ sudoedit /etc/ssh/sshd_config.d/10-ciphers.conf

    If the system does not load /etc/ssh/sshd_config.d, edit /etc/ssh/sshd_config instead.

  6. Add or update one active Ciphers line with the policy that the server should offer.
    /etc/ssh/sshd_config.d/10-ciphers.conf
    Ciphers aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,aes256-ctr

    Use one active Ciphers directive for the final server policy. A list that begins with + appends names to the defaults, - removes names from the defaults, and ^ moves names to the front of the default order.

  7. Validate the updated SSH daemon configuration.
    $ sudo sshd -t

    No output means the configuration parsed successfully.

    Keep a second SSH session or console open until the new policy has been tested from a separate client.

  8. Restart the SSH service so the daemon reads the new cipher list.
    $ sudo systemctl restart ssh

    On RHEL-family systems, the unit is commonly named sshd, so the equivalent command is sudo systemctl restart sshd.

  9. Confirm that the running daemon now exposes the updated cipher list.
    $ sudo sshd -T | grep '^ciphers '
    ciphers aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,aes256-ctr
  10. From a separate client, open a verbose test connection and check the negotiated cipher.
    $ ssh -vv user@host.example.net 'exit'
    ##### snipped #####
    debug1: kex: server->client cipher: aes256-gcm@openssh.com MAC: <implicit> compression: none
    debug1: kex: client->server cipher: aes256-gcm@openssh.com MAC: <implicit> compression: none
    ##### snipped #####

    The two kex lines show the cipher actually selected for the session.

    If the client and server no longer share any cipher, the connection fails with a no matching cipher found negotiation error until at least one common algorithm is restored.

Steps to change SSH ciphers on the client:

  1. Open the per-user OpenSSH client config file, or create it if it does not already exist.
    $ nano ~/.ssh/config

    A host-specific override changes the cipher order for one target without affecting every other SSH connection from the client. Use /etc/ssh/ssh_config only when every user on that system should share the same client policy.

  2. Add or update a host block with the cipher list that should be offered for that target.
    ~/.ssh/config
    Host host-cipher
      HostName host.example.net
      User user
      Ciphers aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,aes256-ctr
  3. Restrict access to the per-user SSH config file.
    $ chmod 600 ~/.ssh/config

    OpenSSH expects private per-user config files to be writable only by the account that owns them.

  4. Show the effective client cipher list for that host alias.
    $ ssh -G host-cipher | grep '^ciphers '
    ciphers aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,aes256-ctr

    ssh -G prints the final client configuration after the matching Host block has been applied.

  5. Make a verbose test connection and confirm the cipher that was actually negotiated.
    $ ssh -vv host-cipher 'exit'
    ##### snipped #####
    debug1: kex: server->client cipher: aes256-gcm@openssh.com MAC: <implicit> compression: none
    debug1: kex: client->server cipher: aes256-gcm@openssh.com MAC: <implicit> compression: none
    ##### snipped #####

    The server→client cipher and client→server cipher lines confirm that the client preference and the server policy still overlap.