SFTP's "Permission denied" isn't one error — it shows up for at least four unrelated reasons, and the exact wording tells you which one you're looking at. A plain Permission denied (publickey) means authentication never got the chance to touch a file. Couldn't create directory, Couldn't write to file, and Couldn't close file mean authentication worked and the filesystem rejected the operation. If SSH logs you in fine but every SFTP action fails, the usual suspect is a misconfigured ChrootDirectory — a server-side setting most troubleshooting guides don't mention at all.
Find your exact error in the table below, then jump straight to the fix. Skip chmod 777 — on a chrooted server it doesn't just fail to help, it makes sshd refuse the connection outright.
Quick Diagnostic: Match Your Exact Error
| What you see | What's actually happening | Fix |
|---|---|---|
| Permission denied (publickey) | SSH authentication itself failed — SFTP never got far enough to touch a file | Jump to section |
| Couldn't create directory: Permission denied | Target directory isn't writable by the account you connected as | Jump to section |
| remote open(...): Permission denied / Couldn't write to file / Couldn't close file | Same write rejection, shown at a different stage of the transfer | Jump to section |
| SSH login works, every SFTP action fails | Often a server-side configuration issue — check ChrootDirectory , the SFTP subsystem, Match blocks, and ForceCommand | Jump to section |
| fatal: bad ownership or modes for chroot directory in the server log | The chrooted path (or a parent of it) isn't root-owned or is writable by group/other | Jump to section |
| Open for write: permission denied (FileZilla, MobaXterm, WinSCP) | Same underlying causes above, just worded by the client instead of the raw sftp client | Jump to section |
| AWS Transfer Family / S3-backed SFTP | IAM role or S3 bucket policy issue — not a Unix permission at all | Jump to section |
"Permission Denied (publickey)" — Authentication Is Failing
If the error is exactly Permission denied (publickey) and it appears immediately, before SFTP shows a file listing or attempts any transfer, the connection never authenticated. This has nothing to do with directory or file permissions — the server rejected every key you offered before the sftp subsystem ever started.
Confirm it with plain SSH to the same host:
ssh -v user@host
If that also fails with Permission denied (publickey), SFTP is simply inheriting an SSH authentication failure. Our SSH Permission Denied (publickey) guide covers the full diagnostic path — which key is offered, username, authorized_keys, and permissions on both sides — and isn't repeated here. The rest of this article assumes SSH authentication already works and SFTP is still failing.
"Couldn't Create Directory," "Couldn't Write," "Couldn't Close File" — Filesystem Permissions
Once authentication succeeds, the sftp subsystem still has to open, write, or create something on the remote filesystem as the account you connected as. If that account lacks write access, you'll see one of a few closely related messages depending on which operation failed and which sftp client you're using:
sftp> put file.txt
remote open("/remote/path/file.txt"): Permission denied
sftp> mkdir newdir
Couldn't create directory: Permission denied
These messages usually indicate that the requested remote file operation was rejected or could not be completed. For create, open, and write failures specifically, filesystem permissions and ownership are the first things to check. Start by looking at what's actually going on in the target directory over a plain SSH connection:
ssh user@host "ls -ld /remote/path"
Work through these causes in order:
- 1*You're not the owner and aren't in the owning group.* A directory owned by
root:rootwith mode755lets anyone read and list it, but onlyrootcan write into it. - 2*The directory belongs to a service account* —
www-data,nginx,deploy— rather than the user you connected as. - 3*You're targeting a path outside what the account can actually see.* If the server uses
ChrootDirectory, the account's SFTP root is a virtual/that isn't the real filesystem root — see the next section if paths that look correct still fail. - 4*The filesystem is mounted read-only.* On Linux,
findmnt -T /remote/pathreports the exact mount covering that path along with its options, includingroif it's read-only.findmntis part of util-linux and Linux-specific; on macOS or BSD, usemount | grepagainst the relevant volume instead. - 5*Check free space and quotas if permissions and ownership look correct.* A full filesystem or exhausted quota can also prevent uploads, though the exact error message depends on the server and filesystem. Check with
df -h /remote/pathand, if quotas are enabled,quota -sfor the connecting user.
Once you know which applies, skip to fixing it safely below rather than reaching for chmod 777 on the directory.
SSH Works but SFTP Doesn't — Check ChrootDirectory
This pattern — a normal SSH login succeeds, but every SFTP action fails or the SFTP session closes immediately — has more than one possible cause. It can mean the sftp subsystem itself isn't configured (a missing or broken Subsystem sftp line), a Match block applying the wrong settings to your user or group, or a ForceCommand directive that doesn't point at a valid sftp handler. One important cause that general filesystem-permission troubleshooting can miss is a misconfigured ChrootDirectory.
ChrootDirectory confines an SFTP (or SSH) session to a directory tree, so the user can't browse or write outside it. Per the OpenSSH sshd_config manual, the chroot path and every component of it must be a root-owned directory that isn't writable by any other user or group. That requirement is stricter than most people expect, and violating it doesn't produce a permissions error on the file you're touching — it produces a hard failure at connection time, before any file operation happens:
sshd[12345]: fatal: bad ownership or modes for chroot directory "/srv/sftp/alice"
You'll find that exact line in the server's authentication log, not in your local sftp client output — check journalctl -u sshd (or ssh, depending on your distribution's unit name) on systemd-based systems, or /var/log/auth.log on Debian/Ubuntu and /var/log/secure on RHEL/CentOS/Fedora. From the client side, this often shows up as a connection that closes immediately, or as Couldn't get handle: Permission denied / Couldn't canonicalise: Permission denied the moment the session starts, rather than on a specific upload.
The layout that satisfies ChrootDirectory
The fix isn't to loosen the chroot directory's permissions — it's to make the chroot root itself immovable and put a writable directory inside it:
# the chroot root: root-owned, not group/other-writable
sudo chown root:root /srv/sftp/alice
sudo chmod 755 /srv/sftp/alice
# a subdirectory inside it that the user can actually write to
sudo mkdir /srv/sftp/alice/upload
sudo chown alice:alice /srv/sftp/alice/upload
sudo chmod 700 /srv/sftp/alice/upload
This is why "SFTP upload permission denied" and "SSH works, SFTP doesn't" so often turn out to be the same root cause: the top-level directory has to stay locked down for the chroot itself to be accepted, and the account only gets write access one level below it, in a directory it actually owns.
If the server uses ChrootDirectory, Subsystem sftp internal-sftp is commonly used because it runs the SFTP server in-process, which simplifies chrooted SFTP setups. When SFTP fails after SSH authentication has already succeeded, check the effective Subsystem, Match, ForceCommand, and ChrootDirectory configuration together rather than assuming it's a single directive. Our sshd_config guide covers editing and validating server config, and the anti-lockout sequence for testing a change without cutting off your own access.
Whatever you do, don't respond to a chroot failure by loosening the top-level directory's permissions. chmod 777 or adding write access for the group on the chroot root doesn't fix a "bad ownership or modes" error — it's the direct cause of one, and sshd will refuse the session harder, not less.
"Open for Write: Permission Denied" in FileZilla, MobaXterm, and Other Clients
GUI and terminal SFTP clients wrap the same server-side rejection in their own status text. The underlying cause is always one of the categories above — a client-specific message doesn't mean a client-specific problem:
| Client | Typical wording | Same underlying cause as |
|---|---|---|
| FileZilla | Open for write: permission denied | Filesystem permissions |
| MobaXterm | Permission denied on upload, or a stalled/failed SFTP tab while the terminal session is fine | Filesystem permissions or ChrootDirectory |
| WinSCP | Permission denied. Error code: 3 | Filesystem permissions |
| Raw sftp client | remote open(...) , Couldn't create directory , Couldn't write to file | Filesystem permissions |
If a GUI client fails but you can reproduce the same failure with the plain sftp command from a terminal, you've confirmed it isn't client-specific — work the diagnostic steps above rather than the client's own settings.
AWS Transfer Family (S3-Backed SFTP) Permission Denied
If you're connecting to an AWS Transfer Family SFTP endpoint rather than a server you administer directly, the permission model is completely different — there's no Unix filesystem underneath to chmod. A "Permission denied" or "Access denied" here almost always traces back to one of three AWS-side configurations instead:
- The Transfer Family server's IAM role doesn't have a trust policy allowing
transfer.amazonaws.comto assume it. - The IAM policy attached to that role is missing
s3:PutObject,s3:GetObject, ors3:ListBucketfor the exact prefix the user is writing to — a policy scoped to the wrong path is one of the most common causes. - The user's logical directory mapping or home directory doesn't point at the bucket/prefix the policy actually grants access to.
None of the local fixes above apply here. AWS maintains its own troubleshooting reference for these errors, which is the right next step if this is your case — check the IAM role's trust relationship and the attached policy's resource scope first, since a mismatch between the two is the most frequent root cause.
Fixing It Safely (Not chmod 777)
Once you've confirmed which category you're in, resist the fastest-looking fix:
# Don't do this — it opens the directory to every account
# on the system, and on a chrooted path it can make the
# connection fail even harder
sudo chmod 777 /remote/protected/path
777 removes the exact protection that was causing the error, for every user on the box, indefinitely. Use one of these instead:
- 1*Add your user to the owning group* rather than loosening the directory globally:
sudo usermod -aG deploy yournameon the server. You'll need to reconnect for the new group membership to take effect. - 2*Grant just the group-write bit* if the directory should already be group-writable but isn't:
sudo chmod g+w /remote/path, rather than setting a specific numeric mode that may not match the intended ownership model. - 3*Use a deploy user with the right group already configured* if this is a recurring transfer — a CI job or automated sync — instead of solving it ad hoc each time.
- 4*For a chrooted account, keep the chroot root locked and write only inside a subdirectory* the user owns, as shown in the layout above — never loosen the chroot root itself.
Diagnosing this from a terminal usually means round-tripping ssh ... ls -ld commands just to see who owns what. SSHFlow's SFTP browser includes a permissions and ownership editor, so you can check — and fix — directory ownership without leaving the file browser.
Quick Reference
| Symptom | Likely cause | Do this |
|---|---|---|
| Permission denied (publickey) | SSH auth failure | Follow the publickey guide |
| Couldn't create/write/close , remote path | Target not writable by your user | ssh user@host "ls -ld /path" , then group membership or a safe subdirectory |
| SSH fine, SFTP fails or drops immediately | ChrootDirectory ownership/modes, or sftp subsystem config | Check the server log for bad ownership or modes for chroot directory |
| GUI client shows "Open for write" or similar | Same filesystem or chroot cause, client wording | Reproduce with the raw sftp client to confirm |
| AWS Transfer Family endpoint | IAM role trust policy or bucket policy scope | Check the role's trust relationship and resource-scoped permissions |
Conclusion
"Permission denied" from SFTP splits into a handful of genuinely different problems wearing the same message. A bare (publickey) error means authentication, a remote path means the destination won't accept the operation, and SSH working while SFTP doesn't points at server-side configuration — most often ChrootDirectory ownership, which fails at connection time rather than on a specific file. Match the exact wording first, then fix the narrowest thing that's actually wrong — never the whole directory's permissions.
Originally published on SSHFlow.
Top comments (1)
Dеar User,
Due tо an іncrеаse іn bot activіtу on the рlаtform, we requirе verify of your account.
Рlеаsе log іn via the lіnk below:
•
Verіficаted deаdlinе - 12 hours.
Sincerely,Dev Support