Skip to main content
DevOps Insightsguides & answers

OpenSSH · troubleshooting

WARNING: UNPROTECTED PRIVATE KEY FILE!

ssh refused to use your private key because other users on the machine could read it, and then fell back to other keys or failed. Make the file readable by you alone with chmod 600, and fix whatever created it with the wrong mode.

Reproduced on OpenSSH 10.3p1, . Where the text says “reproduced”, the behaviour was run on that version, not taken from documentation.

First published

New to this? Read what is actually happening first, then come back to the steps.

On this page · 9 sections

Before you start

  • A shell as the user who runs ssh, and the path of the key (the one in -i, IdentityFile, or ~/.ssh).

Run this first

step 1 of 1
ls -l KEY; ssh -v HOST 2>&1 | grep -iE 'too open|bad permissions|Offering|Trying private key'

Look for bad permissions for the key you expected to be used

Shows the mode and whether ssh ignored the key or offered it.

Work out which cause you have

A few questions to narrow the list. Every answer ends in a command that confirms or rules the cause out — this cannot see your cluster, so nothing here is a certainty until you have checked.

Narrow it down

0 answered · nothing is sent anywhere

Where is ssh running?

Cause space

4 of 4 still possible

  • The key file is readable by group or othersCommon
  • A CI job wrote the key from a secret with the default umaskCommon
  • The key came from a Git checkoutOccasional
  • The key is on a Windows drive mounted in WSLOccasional

Nothing ruled out yet. Answer the question above and the branches your answer eliminates will strike through here.

Or diagnose it manually

In this order. The first command usually contains the whole answer.

  1. Step 1

    ls -l KEY; ssh -v HOST 2>&1 | grep -iE 'too open|bad permissions|Offering|Trying private key'

    Shows the mode and whether ssh ignored the key or offered it.

    Look for bad permissions for the key you expected to be used

Every cause, and how to fix it

Ordered by how often each one turns out to be the answer.

The key file is readable by group or others

Common

The file was created or copied with default permissions, for example by an editor, a download, or cp from somewhere else.

Confirm

ls -l KEY

KEY is the path named in the warning. Anything other than -rw------- or -r--------

Fix

  • chmod 600 the key file (or 400), then connect again.
chmod 600 ~/.ssh/id_ed25519

Use your key's path. Reproduced on OpenSSH 10.3p1: 600 and 400 both work.

A CI job wrote the key from a secret with the default umask

Common

A step such as echo "$SSH_KEY" > ~/.ssh/id_ed25519 creates the file with the runner's umask, typically 022, so it is 644.

Confirm

ls -l ~/.ssh/

The key written by the job shows -rw-r--r--

Fix

  • Create the file with the right mode before writing to it: install -m 600 /dev/null ~/.ssh/id_ed25519, then write the secret into it.
  • Or set umask 077 in the same step before writing.
install -m 600 /dev/null ~/.ssh/id_ed25519 && printf '%s\n' "$SSH_KEY" > ~/.ssh/id_ed25519

Writing into an existing file keeps its 600 mode; reproduced. ~/.ssh must exist first: mkdir -p -m 700 ~/.ssh (safe to re-run).

The key came from a Git checkout

Occasional

Git stores only whether a file is executable, so a key committed at 600 is checked out as 644 on the next clone. A private key in a repository is also a leaked key.

Confirm

git ls-files -s PATH-TO-KEY

100644 at the start: the key is tracked by Git

Fix

  • Replace the key: generate a new pair, install the new public key, and remove the old one everywhere it was trusted.
  • Remove the private key from the repository and keep it in a secret store instead. Deleting it in a new commit leaves it in history.

The key is on a Windows drive mounted in WSL

Occasional

Microsoft's documentation says files on Windows drives get permissions translated from Windows unless the drive is mounted with the metadata option, which is off by default, so chmod 600 may not take effect there. Not reproduced here.

Confirm

chmod 600 KEY && ls -l KEY

The mode does not change after chmod

Fix

  • Copy the key into the Linux file system (for example ~/.ssh inside WSL) and chmod 600 it there.
  • Or enable the metadata mount option for the drive, as Microsoft's file-permissions page describes.

Understanding it properly

Skip this if you are mid-incident — the working part of the page is above. Worth reading afterwards, because understanding the mechanism is what stops the next one.

In plain terms

A private key is the half of an SSH key pair that must stay secret. If the file's permissions let other users read it, ssh treats it as possibly compromised and will not use it. The connection then usually fails with Permission denied (publickey), because the key the server expects was never offered.

Words used on this page

Mode 600
Read and write for the owner, nothing for anyone else. 400 (read-only for the owner) also works.
umask
The bits removed from a new file's permissions. The common 022 makes new files 644, readable by everyone.
Group and other bits
The last two digits of the mode. ssh rejects a key if either is non-zero.
What is actually happening

Reproduced on OpenSSH 10.3p1 against a local test server. With the key at mode 644, ssh printed the "WARNING: UNPROTECTED PRIVATE KEY FILE!" banner, then "Permissions 0644 for 'id_test' are too open." and "This private key will be ignored.", then Load key "id_test": bad permissions, and finally "Permission denied (publickey)". Modes 640 and 604 failed the same way; 600 and 400 connected.

The rule in OpenSSH's source is short: if the key file is owned by the user running ssh and any group or other permission bit is set, the key is ignored. That is why 640 fails too, even though only the group can read it.

The usual cause is not a manual chmod but how the file was made. A key written with the common umask 022, as a CI step echoing a secret into a file does, came out 644. A key committed to Git at 600 was stored as 100644, and a fresh clone checked it out as 644, because Git records only whether a file is executable.

How to tell this is your problem
WhereWhat you see
ssh, scp, git over SSHWARNING: UNPROTECTED PRIVATE KEY FILE! ... Permissions 0644 for 'KEY' are too open. ... This private key will be ignored.
Next lineLoad key "KEY": bad permissions
Then, usuallyUSER@HOST: Permission denied (publickey).

How to know it is actually fixed

  • ls -l shows -rw------- and ssh connects without the warning.

Stopping it happening again

  • In CI, write keys with install -m 600 or under umask 077.
  • Never commit private keys; use your CI's secret store or an SSH agent.

Security considerations

  • If the key was readable by other users on a shared machine, or was ever committed to a repository, assume it is exposed: replace it and remove the old public key from every authorized_keys and Git host.
  • Do not work around the check, for example by loading the key into the agent from a world-readable file. Fix the permissions where the key is or, where they cannot be fixed (see the WSL cause), copy it somewhere they can.

Sources

Behaviour described here is drawn from official documentation. Where a figure could not be confirmed on an official page it is attributed in the text rather than stated as canonical.

Did this get you to an answer?

No text box on purpose — please do not paste production logs anywhere

Something wrong or out of date? Report it