Paramiko’s SFTP client may raise SFTPError: Permission denied
when attempting file operations on remote systems. This comprehensive guide explains Unix file permissions, ownership, umask, ACLs, and Python-based workarounds to diagnose and fix permission issues in SFTP workflows.
1. Understand Unix File Permissions
Unix permissions consist of three bits for user, group, and others (read, write, execute). Check permissions with:
$ ls -l /remote/path/file.txt -rw-r--r-- 1 alice staff 1024 Aug 21 10:00 file.txt
- Owner (alice) can read/write.
- Group (staff) can read.
- Others can read.
2. Verify Ownership and Group
Mismatched ownership can block access. Identify user and group of the SFTP session:
stdin, stdout, _ = ssh.exec_command('id') print(stdout.read().decode()) # uid=1001(alice) gid=50(staff) groups=50(staff),...
3. Adjust Remote File Permissions with chmod
Use chmod
to grant necessary access:
# Grant owner write and group write ssh.exec_command('chmod 664 /remote/path/file.txt') # To allow all users write (use carefully) ssh.exec_command('chmod 666 /remote/path/file.txt')
4. Change Ownership with chown
If you have sudo privileges, change file owner or group:
ssh.exec_command('sudo chown alice:staff /remote/path/file.txt')
sudo
handling may require pty:\nssh.exec_command('sudo -S chown ...', get_pty=True)
.5. Check and Configure umask
umask defines default permissions for new files. A restrictive umask can block group/other write access:
stdin, stdout, _ = ssh.exec_command('umask') print(stdout.read().decode()) # e.g., 0022 # umask 0022 yields 644 default perms; use 0002 for 664 ssh.exec_command('umask 0002')
6. Handle ACLs (Access Control Lists)
Some systems use ACLs for fine-grained permissions. Check with:
$ getfacl /remote/path/file.txt
Modify ACLs via setfacl
:
ssh.exec_command('setfacl -m u:alice:rw /remote/path/file.txt')
7. Use Paramiko SFTP chmod/chown Methods
Paramiko exposes chmod
and chown
directly on SFTP:
sftp = ssh.open_sftp() # Change permissions sftp.chmod('/remote/path/file.txt', 0o664) # Change ownership (if server permits over SFTP) sftp.chown('/remote/path/file.txt', uid=1001, gid=50)
8. Retry Logic and Error Handling
Implement retries for transient permission changes:
import time def safe_put(local, remote, retries=3): for i in range(retries): try: sftp.put(local, remote) return except IOError as e: if 'Permission denied' in str(e) and i < retries-1: time.sleep(1) else: raise
9. Summary Checklist
- Check remote file permissions with
ls -l
. - Verify SFTP user’s
id
matches file owner or group. - Adjust permissions with
chmod
or SFTPchmod()
. - Change ownership via
chown
or SFTPchown()
if permitted. - Review umask to ensure correct defaults for new files.
- Inspect and modify ACLs with
getfacl
/setfacl
. - Wrap file operations in retry logic for resilience.