How to Set SFTP umask in Linux

Last reviewed: by
How to Set SFTP umask in Linux

umask controls which permission bits are removed when a new file or directory is created. For normal shell work, you may set umask in /etc/profile, /etc/login.defs, .bashrc, .profile, or a systemd service. SFTP is different.

OpenSSH SFTP sessions are commonly handled by internal-sftp or sftp-server, and they do not behave like an interactive login shell. That means a user's .bashrc umask is not a reliable way to control SFTP upload permissions, especially for chrooted SFTP users.

This guide explains how to set SFTP umask with OpenSSH, how to apply different umask values per user or group, how to validate sshd_config, and why SFTP umask can remove permissions but cannot add permissions that the client did not request.

The examples below were tested on Ubuntu with OpenSSH 9.9p1. A local-only temporary sshd instance was started on 127.0.0.1:2222 to validate ForceCommand internal-sftp -u 0027 without modifying the real SSH service.

NOTE
For most production setups, use Match User or Match Group with ForceCommand internal-sftp -u 0027. This changes SFTP behavior for selected users without changing SSH/SFTP behavior globally.

Quick Command Summary

Task Command or config
Check current shell umask umask
Show current SFTP subsystem `sshd -T
Show sftp-server supported options /usr/lib/openssh/sftp-server -h
Set global internal-sftp umask Subsystem sftp internal-sftp -u 0027
Set per-group SFTP umask Match Group sftpusers with ForceCommand internal-sftp -u 0027
Set per-user SFTP umask Match User alice with ForceCommand internal-sftp -u 0022
Validate SSHD config sudo sshd -t
Reload SSHD safely sudo systemctl reload sshd or sudo systemctl reload ssh
Verify uploaded mode stat -c '%a %U %G %n' file

What umask Means for SFTP Permissions

Linux file creation normally starts from a requested mode and then applies umask:

Object Common requested mode With umask 0022 With umask 0027 With umask 0077
File 0666 0644 0640 0600
Directory 0777 0755 0750 0700

The important rule is: umask removes permission bits; it does not add missing permission bits.

This local permission test was run to show the behavior:

bash
umask 0077
touch shell-077-file
mkdir shell-077-dir
stat -c '%a %n' shell-077-file shell-077-dir

Tested output:

text
600 shell-077-file
700 shell-077-dir

The same idea applies to SFTP uploads. If the client asks to create a file as 0644, SFTP umask 0027 can reduce it to 0640. If the client asks to create it as 0600, umask 0027 cannot add group read permission.

For general permission changes after files already exist, see chmod recursive examples and chown command examples.


Check the Current OpenSSH SFTP Subsystem

First check how SFTP is currently configured:

bash
sshd -T | grep -i '^subsystem'

Tested output:

text
subsystem sftp /usr/lib/openssh/sftp-server

This system uses the external /usr/lib/openssh/sftp-server binary. Many hardened SFTP-only setups use internal-sftp instead, especially with chroot.

Check OpenSSH server version:

bash
sshd -V 2>&1

Tested output:

text
OpenSSH_9.9p1 Ubuntu-3ubuntu3.2, OpenSSL 3.4.1 11 Feb 2025

Check sftp-server supported options:

bash
/usr/lib/openssh/sftp-server -h 2>&1 | head -n 12

Tested output:

text
usage: sftp-server [-ehR] [-d start_directory] [-f log_facility] [-l log_level]
	[-P denied_requests] [-p allowed_requests] [-u umask]
       sftp-server -Q protocol_feature

The -u umask option is the OpenSSH SFTP server option used in this article.

For broader SSH configuration security, see OpenSSH authentication methods in sshd_config.


Set SFTP umask Globally with Subsystem

Use a global subsystem setting only when the same SFTP umask should apply to all SFTP users.

Edit /etc/ssh/sshd_config:

text
Subsystem sftp internal-sftp -u 0027

This makes internal-sftp apply umask 0027 to new SFTP-created files and directories.

A temporary config with this line was validated with sshd -t:

bash
sshd -t -f /tmp/glc-sshd-test/sshd_config_global
sshd -T -f /tmp/glc-sshd-test/sshd_config_global | grep -i '^subsystem'

Tested output:

text
subsystem sftp internal-sftp -u 0027

Use this global method carefully because it changes every SFTP user's default create permissions.


Set SFTP umask Per Group with Match Group

A per-group SFTP umask is usually cleaner than a global subsystem change. This is common for SFTP-only groups.

Example /etc/ssh/sshd_config block:

text
Subsystem sftp internal-sftp

Match Group sftpusers
    ChrootDirectory /sftp/%u
    ForceCommand internal-sftp -u 0027
    AllowTcpForwarding no
    X11Forwarding no

This applies umask 0027 only to users in the sftpusers group that match the block. It also forces SFTP and disables interactive shell access for those matched sessions.

A temporary Match Group config was validated with sshd -t:

bash
sshd -t -f /tmp/glc-sshd-test/sshd_config_match

Tested output:

text
OK

In a real config, sshd -t prints no output when the syntax is valid. The OK line above was printed by the test wrapper after sshd -t returned successfully.

For chroot setup details, see restrict SFTP user to a specific directory. For group membership management, see add user to group in Linux.


Set SFTP umask Per User with Match User

Use Match User when only one user needs a different SFTP umask:

text
Subsystem sftp internal-sftp

Match User deploy
    ForceCommand internal-sftp -u 0022
    AllowTcpForwarding no
    X11Forwarding no

This applies umask 0022 to SFTP sessions for deploy, but not to other users.

If the user also needs a chroot, include ChrootDirectory and make sure the chroot path is owned by root and not writable by the user. SFTP chroot ownership rules are strict; incorrect ownership causes login failures.


Validate Before Reloading sshd

Always validate SSHD configuration before reload or restart:

bash
sudo sshd -t

If the command returns no output, the syntax is valid. For a custom file, use:

bash
sshd -t -f /tmp/glc-sshd-test/sshd_config_match

Tested output:

text
OK

After validation, reload SSHD if your distribution supports it:

bash
sudo systemctl reload sshd

On Ubuntu and Debian, the service may be named ssh:

bash
sudo systemctl reload ssh

Keep an existing SSH session open while testing. For connection testing and troubleshooting, see test SSH connection commands and SSH command examples.


Tested SFTP Upload with internal-sftp -u 0027

A local-only temporary SSH daemon was started on 127.0.0.1:2222 with this test block:

text
Subsystem sftp internal-sftp

Match User golinuxcloud
    ForceCommand internal-sftp -u 0027
    AllowTcpForwarding no
    X11Forwarding no

Two files were uploaded through SFTP:

  • source-644.txt, mode 0644
  • source-600.txt, mode 0600

The SFTP batch uploaded both files and created a directory:

bash
sftp -q -P 2222 -i /tmp/glc-sftp-umask-test/id_ed25519 \
  -o StrictHostKeyChecking=no \
  -o UserKnownHostsFile=/tmp/glc-sftp-umask-test/known_hosts \
  -b /tmp/glc-sftp-umask-test/batch \
  [email protected]:/tmp/glc-sftp-umask-test/target

Tested output:

text
sftp> put /tmp/glc-sftp-umask-test/source-644.txt source-644.txt
sftp> put /tmp/glc-sftp-umask-test/source-600.txt source-600.txt
sftp> mkdir uploaded-dir
sftp> bye
# effective subsystem in temp config
subsystem sftp internal-sftp

# source permissions
644 root root /tmp/glc-sftp-umask-test/source-644.txt
600 root root /tmp/glc-sftp-umask-test/source-600.txt

# uploaded permissions
640 golinuxcloud golinuxcloud /tmp/glc-sftp-umask-test/target/source-644.txt
600 golinuxcloud golinuxcloud /tmp/glc-sftp-umask-test/target/source-600.txt
750 golinuxcloud golinuxcloud /tmp/glc-sftp-umask-test/target/uploaded-dir

This confirms the common SFTP umask confusion:

  • 0644 uploaded with umask 0027 becomes 0640.
  • 0600 uploaded with umask 0027 stays 0600.
  • A directory created with umask 0027 becomes 0750.

So if your SFTP upload stays 600, the problem may not be that -u 0027 is ignored. The SFTP client may be requesting a restrictive mode, and umask cannot add group-read permission.

For one-line SFTP batch usage, see single-line SFTP command examples. For scripted transfers, see automate SFTP using a shell script.


Troubleshooting SFTP umask

Problem Likely cause What to check
Uploaded file is still 600 Client requested 0600; umask cannot add permissions Compare source/requested mode and upload result with stat
.bashrc umask is ignored SFTP session is not an interactive shell Use internal-sftp -u or sftp-server -u
Group umask does not apply User did not match the Match Group block Check id username and sshd -T -C user=username,host=host,addr=ip
Chroot login fails Chroot directory ownership or permissions are wrong Root must own the chroot path and it must not be writable by the user
SSH config reload fails Syntax error in sshd_config Run sudo sshd -t before reload
File owner or group is unexpected Upload user primary group or directory ACL differs Check id, directory ownership, ACLs, and setgid bit

If permissions display a trailing dot on some systems, see remove dot in Linux permissions. If you need to restrict SSH access by users or groups, see restrict or allow SSH users and groups.


When umask Is Not Enough

Use SFTP umask when you only need to remove permissions from newly created files and directories.

Use other controls when you need stronger behavior:

Need Better control
Force group ownership Set directory group ownership and setgid bit
Apply default ACLs setfacl -d on the upload directory
Restrict user to one directory ChrootDirectory with ForceCommand internal-sftp
Prevent shell access ForceCommand internal-sftp
Harden SSH exposure Key authentication, user restrictions, Fail2ban

For SFTP over IPv6, see use SFTP with IPv6 address in Linux. For SSH brute-force hardening, see Fail2ban SSH configuration.


Frequently Asked Questions

1. How do I set umask for SFTP in Linux?

For OpenSSH internal-sftp, set ForceCommand internal-sftp -u 0027 inside a Match User or Match Group block in sshd_config. For a global SFTP subsystem, use Subsystem sftp internal-sftp -u 0027.

2. Does .bashrc umask apply to SFTP uploads?

Usually no. Non-interactive SFTP sessions handled by internal-sftp or sftp-server do not run the user shell startup files in the same way as an interactive shell, so .bashrc umask is not a reliable SFTP control.

3. What permissions does SFTP umask 0027 create?

For normal uploaded files requested as 0666, umask 0027 results in 0640. For directories requested as 0777, it results in 0750.

4. Why did my SFTP file stay 600 after setting umask 0027?

umask can remove permissions from the mode requested by the client, but it cannot add permissions that were not requested. If the uploaded source or client request is 0600, umask 0027 still leaves it as 0600.

5. Should I use Subsystem sftp internal-sftp -u or ForceCommand internal-sftp -u?

Use Subsystem sftp internal-sftp -u only when the same umask should apply to every SFTP user. Use Match User or Match Group with ForceCommand internal-sftp -u when only selected SFTP users or groups need that umask.

6. Do I need to restart sshd after changing SFTP umask?

Validate the config first with sshd -t, then reload or restart sshd depending on your distribution. Reload is usually safer for active SSH sessions than a full restart.

Summary

To set SFTP umask in Linux with OpenSSH, use internal-sftp -u UMASK or sftp-server -u UMASK. Apply it globally with Subsystem sftp internal-sftp -u 0027, or apply it selectively with a Match User or Match Group block and ForceCommand internal-sftp -u 0027.

For most SFTP-only users, the best pattern is a Match Group block with ForceCommand internal-sftp -u 0027, optional ChrootDirectory, and SSH features such as TCP forwarding disabled. Validate with sshd -t before reloading SSHD.

Remember the key rule: umask removes permissions; it does not add permissions. If an upload is requested as 0600, SFTP umask 0027 will not turn it into 0640.

Omer Cakmak

Linux Administrator

Highly skilled at managing Debian, Ubuntu, CentOS, Oracle Linux, and Red Hat servers. Proficient in bash scripting, Ansible, and AWX central server management, he handles server operations on OpenStack, KVM, Proxmox, and VMware.

  • Debian
  • Ubuntu
  • Linux
  • Red Hat Enterprise Linux