SSH keys on macOS
The key files are OpenSSH's, the Keychain is Apple's, and the agent sits between them. Knowing which of the three is failing is most of the fix.
SSH keys on a Mac are handled by three systems owned by three different
parties, and this page is the index to all of it. The separation matters
because the parts are owned by different people. The key
files and the ssh command come from OpenSSH, an OpenBSD project.
The Keychain that can store your passphrase is Apple's, and so is the patch
that teaches OpenSSH to talk to it. The agent sits between them. When something
goes wrong, knowing which of those three you are arguing with is most of the
diagnosis, and it is the piece almost no troubleshooting page bothers to
establish before handing you a command to paste.
What actually happens when you run ssh on a Mac?
Five things happen in order, and every failure mode on this site is a
failure of one of them. First, ssh reads its configuration, which
means ~/.ssh/config and then /etc/ssh/ssh_config, and
the first matching value for any option wins. Second, it resolves the host and
opens a TCP connection. Third, the two sides negotiate a protocol version, a
key exchange method, and a set of acceptable algorithms — this is where a
server too old or too new for your client fails. Fourth, the server proves its
identity with its host key, which your client checks against
~/.ssh/known_hosts. Only fifth, after all of that, does your own
key get used to prove who you are. An error at step four is about the
server's identity. An error at step five is about yours. They are frequently
confused.
Where do the files live, and what has permission to read them?
| Path | What it is | Permissions OpenSSH expects |
|---|---|---|
~/.ssh/ | Everything below | 700 |
~/.ssh/id_ed25519 | A private key. Never leaves the machine. | 600 |
~/.ssh/id_ed25519.pub | The matching public key. Safe to publish. | 644 |
~/.ssh/config | Per-host client settings | 600 |
~/.ssh/known_hosts | Host keys you have accepted before | 644 |
~/.ssh/authorized_keys | Only relevant when your Mac is the server | 600 |
OpenSSH refuses to use a private key whose file is readable by other users
on the machine, and it says so plainly when it happens. On a single-user Mac
this rarely bites, but it does after you restore a home directory from a backup
or copy keys off a Linux box with a different umask. The fix is
chmod 600 on the private key and chmod 700 on the
directory. Note that the public key being world-readable is not a problem and
never was — that is the entire point of a public key.
Is a passphrase on the key worth the trouble?
Yes, and on macOS the trouble is a one-time cost rather than a recurring one. A private key without a passphrase is a plain file: anyone who can read it can become you on every server that trusts it, including a process running as your user, a synced backup, or whoever ends up with the laptop. A passphrase means the file alone is not enough. The objection to passphrases has always been the typing, and that objection is answered on macOS by the login Keychain holding the passphrase and the agent holding the decrypted key — which is configuration you set once and never think about again. The two options that enable it both ship disabled, which is why so many people conclude passphrases are impractical and generate keys without one.
-
ssh-agent and the macOS Keychain
Why your Mac asks every time, the two options that cause it, and why
ssh-add -Kin your shell profile is the wrong fix. -
Ed25519 or RSA in 2026?
What OpenSSH disabled by default in 2021, why that is about signatures rather than keys, and what to do about a server that has not caught up.
What is the agent for, in one paragraph?
The ssh-agent is a small process that holds decrypted private
keys in memory and performs signatures on request, so that the key material
itself never has to be handed to anything else. When you connect,
ssh asks the agent "sign this challenge with the key whose
fingerprint is X", and the agent does it. That is why an agent can be forwarded
to a remote host without copying your key there, and it is also why forwarding
an agent to a machine you do not trust is dangerous: anyone with root on that
machine can ask your agent to sign things while the connection is open. On
macOS the agent is started for you and reachable through the
SSH_AUTH_SOCK environment variable, which you can inspect with
echo $SSH_AUTH_SOCK in any terminal.
What this section deliberately does not cover
Server-side configuration is out of scope here. Hardening
sshd_config, choosing an authentication policy for a fleet, and
running a certificate authority for SSH are all real subjects, and treating
them as a footnote to a client-side page would do them badly. This section is
about the Mac in front of you: the keys on it, the agent it runs, and the
Keychain that can hold a passphrase for you. When a page here needs a
server-side fact to make sense, it states the fact and links the primary
documentation rather than growing a tutorial around it.
Who writes this. OnePasswordManager Ltd, the developers of SSHMount, a paid macOS app on the Mac App Store. Everything in this section concerns OpenSSH and macOS as they ship, and none of it requires our software or anyone else's. We say who we are on every page because a site about handling private keys that is coy about its own identity has the priorities backwards. More on how this site is run.
Sources
Every technical claim above is checked against one of these. Where a manual page is quoted, it is the copy shipped by the vendor named, not a third-party summary of it.
- ssh(1), the manual page shipped with macOS — https://keith.github.io/xcode-man-pages/ssh.1.html
- ssh_config(5), the manual page shipped with macOS — https://keith.github.io/xcode-man-pages/ssh_config.5.html
- OpenSSH, upstream project home — https://www.openssh.com/