ssh-keygen command reference and cheat sheet

ssh-keygen creates, converts and inspects SSH keys, and manages known_hosts and certificates. The options you will actually use, with examples.

updated

Quick answer. ssh-keygen -t ed25519 -C "[email protected]" creates a new key pair in ~/.ssh. -p changes its passphrase, -l shows its fingerprint and -R forgets a server's old host key. Examples for each follow.

The commands you need most

ssh-keygen -t ed25519 -C "[email protected]"     # create a new key (recommended)
ssh-keygen -t rsa -b 4096 -C "[email protected]"  # RSA, for systems without Ed25519
ssh-keygen -p -f ~/.ssh/id_ed25519              # change the passphrase
ssh-keygen -lf ~/.ssh/id_ed25519.pub            # show the fingerprint
ssh-keygen -y -f ~/.ssh/id_ed25519              # print the public key
ssh-keygen -R example.com                       # forget a host's old key

Options

FlagWhat it does
-t typeKey type: ed25519, rsa, ecdsa, or ed25519-sk / ecdsa-sk for FIDO2 hardware keys. Default ed25519 in OpenSSH 9.5 and later, rsa before.
-b bitsKey size. RSA: 3072 by default, 2048 minimum in practice, 4096 common. ECDSA: 256, 384 or 521. Ignored for Ed25519.
-C commentComment stored with the key and appended to the public key line, usually an email or user@host.
-f fileKey file to create or operate on. The public key is written to the same name plus .pub.
-N passphraseNew passphrase, non-interactively. -N "" creates an unencrypted key.
-P passphraseOld passphrase, for -p and for reading encrypted keys in scripts.
-a roundsbcrypt_pbkdf rounds used to encrypt the private key. Default 16; higher is slower to unlock and to brute-force.
-Z cipherCipher that encrypts the private key file. Default aes256-ctr; ssh -Q cipher lists the alternatives.
-pChange, add or remove the passphrase of an existing key, without changing the key.
-cChange the comment of an existing key, together with -C.
-lPrint the fingerprint of a key file, authorized_keys or known_hosts.
-E hashFingerprint hash for -l: sha256 (default) or md5.
-BPrint the bubblebabble digest of a key, an older pronounceable fingerprint format.
-vVerbose. With -l, also draws the randomart image.
-yRead a private key and print its public key, to recreate a lost .pub file.
-eExport a key to another format, by default RFC 4716 (SSH2) used by some commercial SSH servers.
-iImport a key from RFC 4716 or PKCS8 format into OpenSSH format.
-m formatFormat for -e, -i and new private keys: RFC4716, PKCS8 or PEM.
-qQuiet. Suppresses the progress output and randomart, for scripts.
-R hostRemove all keys for a host from known_hosts.
-F hostFind a host in known_hosts, also in hashed files.
-HHash every host name in known_hosts, so the file does not reveal where you connect.
-ACreate any missing host keys in /etc/ssh with default settings, as installers do.
-r hostPrint SSHFP DNS records for a public key, for publishing host key fingerprints.
-O optionExtra options, for example resident and verify-required for FIDO keys, or certificate options with -s.
-KDownload resident keys from a connected FIDO2 authenticator into the current folder.
-w providerUse a different FIDO middleware library instead of the built-in one.
-D pkcs11Print the public keys held on a PKCS#11 token such as a smart card, via its library.
-s ca_keySign a public key with a CA key to create a certificate. Used with -I, -n and -V.
-I idKey identity recorded in a certificate and in server logs.
-n principalsUsers (or, with -h, host names) a certificate is valid for, comma separated.
-V intervalCertificate validity, for example +52w or 20260101:20270101.
-z serialSerial number embedded in a certificate, so it can be revoked individually.
-hCreate a host certificate instead of a user certificate.
-UThe CA key for -s or -Y sign lives in ssh-agent; pass its public key to -s.
-LPrint the contents of a certificate.
-kCreate a key revocation list (KRL); -u updates an existing one.
-QTest whether keys are listed in a KRL.
-Y opSign or verify arbitrary data: sign, verify, find-principals, check-novalidate.
-M opGenerate (generate) or test (screen) Diffie-Hellman group exchange moduli.

The full list is in man ssh-keygen. -o from older guides has been the default since OpenSSH 7.8.

Generate keys

A standard key with a passphrase

ssh-keygen -t ed25519 -C "[email protected]"

It asks for a file name (Enter keeps ~/.ssh/id_ed25519) and a passphrase. On OpenSSH 10 the session looks like this:

Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/you/.ssh/id_ed25519):
Enter passphrase for "/home/you/.ssh/id_ed25519" (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/you/.ssh/id_ed25519
Your public key has been saved in /home/you/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:I2McFhOvOOgBGIf3aLmk0z7TTKxZoLZ32hK6Bxbk7Tw [email protected]

Which type to choose is covered in Ed25519 vs RSA vs ECDSA; platform walkthroughs are in the Linux, macOS and Windows guides.

RSA and ECDSA keys

ssh-keygen -t rsa -b 4096 -C "[email protected]"
ssh-keygen -t ecdsa -b 384 -C "[email protected]"

A second key under its own name

ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_work -C "[email protected]"

A key for automation, without a passphrase

ssh-keygen -t ed25519 -N "" -q -f ./deploy_key -C "deploy@ci"

Non-interactive, for CI. Restrict the key with command= and from= in authorized_keys.

A stronger passphrase derivation

ssh-keygen -t ed25519 -a 64 -C "[email protected]"

More rounds make every unlock, and every guess by an attacker who stole the file, slower. See KDF rounds.

A key in the legacy PEM format

ssh-keygen -t rsa -b 4096 -m PEM -f ./legacy_key

Only for software that cannot read the OpenSSH format. PEM private keys are weaker at rest, so convert back when you can.

Change the passphrase and comment

Change, add or remove the passphrase

ssh-keygen -p -f ~/.ssh/id_ed25519

The key and fingerprint stay the same. An empty new passphrase removes protection. In scripts, pass both with -P "old" -N "new", and raise the KDF rounds at the same time with -a.

Change the comment

$ ssh-keygen -c -C "new comment" -f ~/.ssh/id_ed25519
Old comment: [email protected]
Comment 'new comment' applied

The comment is only a label; servers ignore it. Changing it also rewrites the .pub file, but copies of the public key already installed elsewhere keep the old comment.

Read the public key from a private key

ssh-keygen -y -f ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.pub

Recreates a lost or damaged .pub file. For an encrypted key it asks for the passphrase. It is also the surest way to check that a private and a public key belong together: compare the output with the .pub file.

Fingerprints and randomart

$ ssh-keygen -lf ~/.ssh/id_ed25519.pub
256 SHA256:I2McFhOvOOgBGIf3aLmk0z7TTKxZoLZ32hK6Bxbk7Tw [email protected] (ED25519)

$ ssh-keygen -E md5 -lf ~/.ssh/id_ed25519.pub
256 MD5:b5:23:6d:0b:dc:ac:67:62:85:a1:dd:80:15:4c:52:2c [email protected] (ED25519)

$ ssh-keygen -lvf ~/.ssh/id_ed25519.pub

-l also reads authorized_keys and known_hosts, one line of output per key, and standard input with -f -. Everything about fingerprints is in SSH key fingerprints.

Convert formats: PEM, PKCS8, RFC 4716

FormatLooks likeUsed by
OpenSSH private-----BEGIN OPENSSH PRIVATE KEY-----Current OpenSSH, the default
OpenSSH publicssh-ed25519 AAAA... commentauthorized_keys, GitHub, every SSH server
PEM-----BEGIN RSA PRIVATE KEY-----Older tools and libraries
PKCS8-----BEGIN PUBLIC KEY-----OpenSSL and TLS tooling
RFC 4716---- BEGIN SSH2 PUBLIC KEY ----Some commercial SSH servers and appliances

Rewrite a private key in the old PEM format

ssh-keygen -p -m PEM -f ~/.ssh/id_rsa

For old tools that only read -----BEGIN RSA PRIVATE KEY-----. This rewrites the key in place, so copy it first. Running ssh-keygen -p without -m converts it back to the OpenSSH format.

Export a public key as RFC 4716 or PKCS8

$ ssh-keygen -e -f ~/.ssh/id_ed25519.pub
---- BEGIN SSH2 PUBLIC KEY ----
Comment: "256-bit ED25519, converted by you@laptop from OpenSSH"
AAAAC3NzaC1lZDI1NTE5AAAAICjC3B8SRdvp0H36PKIVoOSLOR8PA2GXw+6tRPH+FQ0z
---- END SSH2 PUBLIC KEY ----

$ ssh-keygen -e -m PKCS8 -f ~/.ssh/id_rsa.pub

Import an RFC 4716 or PKCS8 public key

ssh-keygen -i -f key_from_vendor.pub >> ~/.ssh/authorized_keys
ssh-keygen -i -m PKCS8 -f public.pem

Work with known_hosts

ssh-keygen -F example.com         # show stored keys for a host
ssh-keygen -R example.com         # remove them after a legitimate key change
ssh-keygen -R "[example.com]:2222" # a host on a non-standard port
ssh-keygen -H                     # hash every host name in the file

-R and -H keep the previous version as known_hosts.old. After -H, delete that file, since it still contains the readable names. Use -f to work on a file other than ~/.ssh/known_hosts.

Sign and verify files and commits

Since OpenSSH 8.1, ssh-keygen signs arbitrary data. Git uses this for commit signing.

ssh-keygen -Y sign -f ~/.ssh/id_ed25519 -n file release.tar.gz
ssh-keygen -Y verify -f allowed_signers -I [email protected] -n file -s release.tar.gz.sig < release.tar.gz

The first command writes release.tar.gz.sig. The allowed_signers file lists trusted keys, one per line, as [email protected] ssh-ed25519 AAAA.... A good signature prints:

Good "file" signature for [email protected] with ED25519 key SHA256:I2McFhOvOOgBGIf3aLmk0z7TTKxZoLZ32hK6Bxbk7Tw
  • -n is the namespace. A signature made for one namespace does not verify in another, so a file signature cannot be passed off as a git signature. Git uses git.
  • -Y find-principals -s file.sig -f allowed_signers tells you who made a signature.
  • -Y check-novalidate -n file -s file.sig < file checks that a signature is intact without deciding whether the signer is trusted.

SSH certificates

A CA key signs user keys with an expiry date, and servers trust the CA with one TrustedUserCAKeys line in sshd_config. No more copying public keys to every server, and access ends by itself when the certificate expires.

User certificates

ssh-keygen -t ed25519 -f ca_user_key -C "user CA"
ssh-keygen -s ca_user_key -I alice -n alice,deploy -V +8h ~/.ssh/id_ed25519.pub
ssh-keygen -L -f ~/.ssh/id_ed25519-cert.pub

The second command writes id_ed25519-cert.pub, valid for eight hours as users alice and deploy. ssh picks it up automatically next to the key. -L shows what is inside:

        Type: [email protected] user certificate
        Public key: ED25519-CERT SHA256:I2McFhOvOOgBGIf3aLmk0z7TTKxZoLZ32hK6Bxbk7Tw
        Signing CA: ED25519 SHA256:upxCLwGfORW/m0nebVB5eDsOeF4LgBghrwbM7m6TqL8 (using ssh-ed25519)
        Key ID: "alice"
        Serial: 0
        Valid: from 2026-10-09T05:42:00 to 2026-10-09T13:43:09
        Principals:
                alice
                deploy
        Critical Options: (none)
        Extensions:
                permit-X11-forwarding
                permit-agent-forwarding
                permit-port-forwarding
                permit-pty
                permit-user-rc

Restrict a certificate with -O: -O force-command=/usr/local/bin/backup, -O source-address=203.0.113.0/24, or -O clear to drop all the permit extensions and add back only what is needed, such as -O permit-pty. On the server:

TrustedUserCAKeys /etc/ssh/user_ca.pub

Host certificates

The CA can also sign host keys, so clients trust every server it signed without the first-connection prompt:

ssh-keygen -s ca_host_key -h -I web01 -n web01.example.com -V +52w /etc/ssh/ssh_host_ed25519_key.pub

Point sshd at the result with HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub, and add one line to the clients' known_hosts: @cert-authority *.example.com ssh-ed25519 AAAA... with the host CA's public key.

Revoke keys with a KRL

A key revocation list is a compact file of keys and certificates sshd must refuse, useful when a key you cannot delete from every authorized_keys leaks, or for revoking certificates before they expire.

ssh-keygen -k -f /etc/ssh/revoked_keys stolen_key.pub
ssh-keygen -k -u -f /etc/ssh/revoked_keys another_key.pub
ssh-keygen -Q -f /etc/ssh/revoked_keys suspect_key.pub

The first creates the list, the second adds to it, the third checks a key against it. Enable it with RevokedKeys /etc/ssh/revoked_keys in sshd_config.

FIDO2 security keys

ssh-keygen -t ed25519-sk -O resident -O verify-required -C "yubikey"

The key lives on the token. resident lets ssh-keygen -K fetch it on another computer; verify-required asks for the PIN as well as a touch. Needs OpenSSH 8.2 on both ends.

OptionEffect
-O residentStore the key handle on the token, so it can be recovered with -K.
-O verify-requiredRequire the token's PIN or biometric check on every use.
-O application=ssh:nameKeep several resident keys apart on one token. Must start with ssh:.
-O no-touch-requiredAllow use without a touch. The server must also allow it with no-touch-required in authorized_keys.
-O user=nameUser name stored with a resident key.
cd ~/.ssh && ssh-keygen -K

Downloads the resident keys from a connected token as key files in the current folder. If your token lacks Ed25519 support, use -t ecdsa-sk.

Host keys and SSHFP records

sudo ssh-keygen -A
ssh-keygen -r host.example.com -f /etc/ssh/ssh_host_ed25519_key.pub

-A creates any missing host keys in /etc/ssh with an empty passphrase, which is what package installers run. -r prints SSHFP records for publishing the host key fingerprint in DNS. To give a reinstalled server a fresh identity, delete its ssh_host_* files, run ssh-keygen -A and restart sshd; clients will then see the host-key-changed warning.

Moduli for Diffie-Hellman group exchange

/etc/ssh/moduli holds the prime groups sshd uses for the diffie-hellman-group-exchange key exchange. Current clients and servers usually agree on curve25519 or a post-quantum hybrid instead, so this matters only for old clients. Generating your own is a two-step job that takes hours:

ssh-keygen -M generate -O bits=3072 moduli-3072.candidates
ssh-keygen -M screen -f moduli-3072.candidates moduli-3072

A common hardening step is simpler: drop the short groups from the shipped file with awk '$5 >= 3071' /etc/ssh/moduli, written to a new file that then replaces the original.

No terminal at hand?

The sshkeygen.dev generator writes the same key files in your browser.

FAQ

What does ssh-keygen do without any options?

It creates a new key pair interactively, asking for a file name and a passphrase. On OpenSSH 9.5 and later the type is Ed25519, saved as ~/.ssh/id_ed25519; older versions create an RSA key. Passing -t ed25519 makes the result the same everywhere.

How do I generate a key without any prompts?

Give the file and the passphrase on the command line: ssh-keygen -t ed25519 -f ./key -N "" -q. If the file exists, ssh-keygen still asks whether to overwrite it, so remove the old file first in scripts.

What is the difference between ssh-keygen -l and -y?

-l prints the short fingerprint of a key. -y prints the whole public key line from a private key file, which is how you rebuild a missing .pub file.

Can ssh-keygen convert a PuTTY .ppk key?

No. Use PuTTYgen: load the .ppk and export it as an OpenSSH key, or on Linux and macOS run puttygen key.ppk -O private-openssh -o id_ed25519. The other direction also needs PuTTYgen.

What does the -o option do?

It used to select the newer OpenSSH private key format. That format has been the default since OpenSSH 7.8, so -o is accepted but does nothing on current versions.

How do I see which version of ssh-keygen I have?

ssh-keygen has no version flag; -V sets a certificate's validity. Run ssh -V, since ssh and ssh-keygen come from the same OpenSSH release.

Does ssh-keygen need root?

Only to write files that root owns, such as host keys in /etc/ssh. Personal keys, fingerprints, conversions and known_hosts edits run as your own user.