The Error ScenarioIt happens to the best of us. You’ve just finished a long coding session, you type git push origin main, and instead of a success bar, your terminal hits you with a brick wall:
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.
This error means your Mac tried to connect to a server like GitHub via SSH, but the handshake failed. The server either didn't see a public key it recognized or your machine didn't offer one at all. It is a common roadblock, especially after a fresh macOS update or when setting up a new MacBook Pro.
Why this happens on macOSOn macOS Sonoma or Ventura, this usually boils down to four specific culprits:
- Missing Keys: You haven't generated an SSH key pair yet.- Unlinked Identity: Your key exists locally but hasn't been uploaded to your GitHub or GitLab profile.- The Reboot Reset: The macOS SSH agent often "forgets" your keys after you restart your computer.- Strict Permissions: SSH is paranoid. If your
.sshfolder is too "talkative" (accessible by other users), macOS will ignore your keys entirely for security.## Step 1: Check for existing SSH keysDon't waste time creating a duplicate if you don't have to. First, see what's already in your locker by running:
ls -al ~/.ssh
Check the list for id_ed25519.pub or id_rsa.pub. If you see these files, you’re halfway there—skip to Step 3. If the directory is missing or empty, it’s time to build a new one.
Step 2: Generate a new SSH keyModern security standards favor the Ed25519 algorithm. It’s faster and more secure than the aging RSA standard. Generate your key with this command:
ssh-keygen -t ed25519 -C "your_email@example.com"
Press Enter to accept the default file location (/Users/yourname/.ssh/id_ed25519). When asked for a passphrase, provide one. It adds a vital layer of security if your laptop is ever lost or stolen.
Step 3: Configure the macOS SSH AgentThis is the most common point of failure for Mac users. Even if the key exists, macOS won't automatically use it unless told to do so. Start the agent in the background:
eval "$(ssh-agent -s)"
Now, we need to make this configuration permanent so it survives a reboot. Create or open your SSH config file:
nano ~/.ssh/config
Paste these specific lines into the editor:
Host github.com
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_ed25519
Note: If you are using an older RSA key, change the last line to ~/.ssh/id_rsa.
Save and exit by hitting Ctrl+O, Enter, and Ctrl+X. Finally, link the key to your macOS Keychain:
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
Step 4: Upload your Public KeyGitHub needs to know your key belongs to you. Copy the contents of your public key directly to your clipboard with this shortcut:
pbcopy < ~/.ssh/id_ed25519.pub
```- Navigate to your GitHub **Settings**.- Click **SSH and GPG keys** in the left sidebar.- Select **New SSH Key**.- Give it a clear label like "M3 MacBook Air - Office" and paste the code into the **Key** field.## Step 5: Tighten File PermissionsIf your permissions are wrong, SSH will silently fail. Your `.ssh` folder should be a private vault. Set the directory to `700` (read/write/execute for you only) and the key to `600` (read/write for you only):
chmod 700 ~/.ssh chmod 600 ~/.ssh/id_ed25519
If you're ever unsure about these numbers, a [Unix Permissions Calculator](https://toolcraft.app/en/tools/developer/unix-permissions) can help you visualize the bitmask. For example, `600` ensures no "Group" or "World" users can even peek at your private data.
## Step 6: The Moment of TruthTest your connection without actually trying to push code:
ssh -T git@github.com
A successful setup will return: *"Hi [your-username]! You've successfully authenticated, but GitHub does not provide shell access."*
### Quick Troubleshooting- **Wrong Protocol:** Double-check your remote URL. Use `git remote -v`. If it starts with `https://`, your SSH keys won't be used. Switch it using `git remote set-url origin git@github.com:user/repo.git`.- **Multiple Accounts:** If you mix work and personal accounts, your `~/.ssh/config` needs separate `Host` entries for each to avoid identity confusion.

