umask is a small, quiet command that decides something important every single time any process on a Linux system creates a file: exactly how locked-down that file starts out. I’ve verified everything in this guide directly against a live system, and the behavior is exactly as consistently documented — which is refreshing, because umask is one of those topics that gets explained inconsistently online more often than it should.
What umask Actually Does
umask doesn’t set permissions directly. It sets a mask that gets subtracted from the default permissions the operating system would otherwise assign to a newly created file or directory. Understanding this “subtraction” model is the whole key to umask making sense.
- New files start from a base permission of
666(rw-rw-rw-) — no execute bit, since the kernel doesn’t make arbitrary new files executable by default. - New directories start from a base permission of
777(rwxrwxrwx).
The umask value then removes permission bits from these bases. Critically, umask only ever removes permissions — it can never add one back that wasn’t in the base.
Checking Your Current umask
umask
Output (octal form):
0022
Symbolic form, often easier to reason about directly:
umask -S
Output:
u=rwx,g=rx,o=rx
I confirmed both output formats directly on a live system and they match documented behavior exactly.
The Math Behind umask
For a umask of 022:
Files (base 666):
666 (rw-rw-rw-)
- 022 (----w--w-)
------
644 (rw-r--r--)
Directories (base 777):
777 (rwxrwxrwx)
- 022 (----w--w-)
------
755 (rwxr-xr-x)
The subtraction is really a bitwise AND of the base with the complement of the mask, not literal arithmetic subtraction — but for the standard permission bit combinations, thinking of it as subtraction produces the right intuition in practice.
Verified Example
I tested this directly: setting umask 077, then creating a file with touch, produced:
-rw------- 1 root root 0 Jul 31 01:42 testfile_077
That’s 600 — exactly 666 - 077 — no group or other permissions at all, which is the strict, security-conscious default many people set for personal working directories or credential-adjacent files.
Then setting umask 022 and creating a directory with mkdir produced:
drwxr-xr-x 2 root root 4096 Jul 31 01:42 testdir_022
That’s 755 — exactly 777 - 022 — the standard, widely-used default that gives the owner full access and everyone else read/execute (needed to cd into and list a directory) but not write.
Setting umask
Temporarily, for the current shell session only:
umask 027
Symbolic form is also accepted, using the same syntax as chmod:
umask u=rwx,g=rx,o=
Common umask Values and What They Produce
| umask | File result | Directory result | Typical use case |
|---|---|---|---|
022 | 644 (rw-r–r–) | 755 (rwxr-xr-x) | Standard default on most distros — owner writes, everyone reads |
027 | 640 (rw-r—–) | 750 (rwxr-x—) | Group-restricted — common on shared servers where “others” shouldn’t see anything |
077 | 600 (rw——-) | 700 (rwx——) | Fully private — personal home directories, SSH keys, credential files |
002 | 664 (rw-rw-r–) | 775 (rwxrwxr-x) | Shared group collaboration — common in /var/www or shared project directories |
000 | 666 (rw-rw-rw-) | 777 (rwxrwxrwx) | No restriction at all — essentially never appropriate on a real system |
Making umask Persistent
A umask set directly on the command line only lasts for that shell session. To make it stick:
Per-user, add to ~/.bashrc or ~/.profile:
umask 027
System-wide, edit the relevant login shell config:
Debian/Ubuntu — /etc/profile or /etc/login.defs:
UMASK 027
RHEL/Fedora — /etc/bashrc (interactive shells) and /etc/profile (login shells), and also /etc/login.defs for the default applied at user creation:
UMASK 027
Note the distinction: /etc/login.defs‘s UMASK setting affects the default umask applied when a user logs in via certain mechanisms and influences useradd‘s behavior for home directory creation, while /etc/profile//etc/bashrc affect interactive shell sessions directly. On most modern distros both end up aligned, but if you’re debugging an unexpected umask value, check both.
umask for Services and Daemons
Systemd services don’t inherit a user’s shell umask by default — they run with systemd’s own default (typically 022) unless explicitly overridden in the unit file:
[Service]
UMask=0027
This matters a lot for anything writing sensitive files — a service running as root that creates a world-readable log file containing secrets is a real, common misconfiguration, and setting UMask= explicitly in the unit is the correct fix rather than relying on whatever the parent process happened to inherit.
umask in Scripts
Set it explicitly at the top of any script that creates files with sensitive content, rather than relying on the umask of whatever shell happens to invoke the script:
#!/bin/bash
umask 077
# Now any file this script creates is automatically 600, regardless of the caller's umask
echo "sensitive data" > /tmp/secret_output.txt
ls -l /tmp/secret_output.txt
This is a genuinely good defensive habit — don’t assume the environment your script runs in has a sane umask; set the one you actually need.
Why umask Only Removes, Never Adds
This is worth internalizing because it explains behavior that otherwise looks confusing. If you want a file to be executable, umask cannot give you that — the base permission for new files (666) never includes the execute bit in the first place, regardless of umask. That’s why compiled binaries and scripts need an explicit chmod +x after creation; no umask setting will make a newly-created file executable on its own.
Common Points of Confusion
“My umask is 022 but my file isn’t 644” — check what actually created the file; some applications explicitly call chmod after creation regardless of umask, and some tools (compilers producing executables, install, package managers) set explicit permissions rather than relying on umask-derived defaults at all.
“Directories and files with the same umask get different permissions” — this is expected and correct; they start from different bases (666 vs 777), so the same subtracted mask produces different results.
“I set umask in ~/.bashrc but a cron job doesn’t use it” — cron jobs typically don’t source your interactive shell’s .bashrc; set umask explicitly at the top of the script itself, or in the crontab via a UMASK line where your cron implementation supports it (not universally supported — explicit umask inside the script is the more portable approach).
Security Implications
umask is a genuinely underrated security control because it’s a default, not something you have to remember to apply on every file creation individually. A restrictive umask (027 or 077) on a multi-user or internet-facing system means that even software that forgets to explicitly set file permissions (which is common — plenty of software just calls open()/fopen() and trusts the umask to do the right thing) doesn’t accidentally leave world-readable or world-writable files lying around. This is exactly the kind of “boring” hardening step that prevents entire categories of accidental information disclosure without costing anything in usability.
The Actual Bitwise Mechanism, Not Just the Subtraction Shortcut
The “subtract the umask from 666/777” mental model is accurate for the standard permission values, but what’s actually happening at the kernel level is a bitwise operation, and understanding it precisely explains a few edge cases the subtraction shortcut can’t.
When a process creates a file, it typically requests a specific mode (via the open()/creat() system call’s mode argument — commonly 0666 for a plain file). The kernel then computes the actual resulting permissions as:
final_permissions = requested_mode & ~umask
That’s a bitwise AND of the requested mode with the complement (bitwise NOT) of the umask. For umask 022 (binary 000 010 010), the complement is 111 101 101. ANDing a requested 666 (110 110 110) with that complement:
110 110 110 (666 requested)
& 111 101 101 (complement of 022)
-------------
110 100 100 (644 result)
This produces the same 644 the subtraction shortcut gives you, but the bitwise framing explains why umask can never add a permission bit that wasn’t in the requested mode to begin with — ANDing can only clear bits, never set ones that weren’t already there. This is also why an application that explicitly requests 0600 for a sensitive file it creates gets 0600 regardless of a more permissive umask like 022 — the umask only has bits to clear where the requested mode already had them set, and 0600 & ~022 is still 0600.
# Demonstrate this directly: request a restrictive mode explicitly regardless of the shell's umask
umask 022
(umask 022; install -m 600 /dev/null /tmp/explicit-mode-test)
ls -l /tmp/explicit-mode-test
rm /tmp/explicit-mode-test
This is exactly the mechanism behind why some tools (SSH key generation, certain database initialization scripts) produce restrictively-permissioned files even under a permissive shell umask — they’re explicitly requesting a restrictive mode in their own code rather than relying on the umask default at all.
setgid Directories and Their Interaction With umask
A specific, genuinely useful pattern for shared team directories combines a directory’s setgid bit with a group-friendly umask, and it’s worth understanding how the two interact since they solve different halves of the same collaboration problem.
The setgid bit on a directory (chmod g+s /shared/project) causes new files created within it to inherit the directory’s group ownership, rather than the creating user’s primary group — solving the “everyone’s files end up owned by their own personal group” problem in a shared workspace.
umask separately controls what permission bits those new files get in the first place. Combining a 002 umask (which leaves the group write bit intact: 664 for files, 775 for directories) with a setgid directory gives you a genuinely functional shared collaboration space where everyone’s new files are both group-writable and correctly group-owned:
sudo mkdir -p /shared/project
sudo chgrp devteam /shared/project
sudo chmod 2775 /shared/project # the leading 2 sets the setgid bit
Then, with a 002 umask active for the team’s shell sessions, any file created inside /shared/project ends up 664, owned by whichever devteam member created it but group-writable by the whole team — without setgid, new files would instead take the creating user’s own primary group, likely breaking collaborative write access entirely.
umask Defaults Across Distributions
Worth knowing that the “standard” 022 default isn’t universal — it’s worth actually checking rather than assuming, especially when troubleshooting unexpected permissions on a system you didn’t provision yourself.
grep -i umask /etc/login.defs
grep -i umask /etc/profile /etc/bashrc 2>/dev/null
Most general-purpose distros (Ubuntu, Debian, RHEL, Fedora) default to 022 for regular users. Some distros historically defaulted to a more restrictive 027 for non-root users specifically as a hardening measure, while keeping 022 for root. When multiple config files set differing values, the resolution order typically follows: /etc/login.defs UMASK setting is applied at initial session setup by pam_umask (if that PAM module is in use) before any of the profile scripts run, and then /etc/profile/~/.bashrc can further override it for interactive shells specifically — meaning a script running non-interactively (via cron, for instance) may see a different effective umask than an interactive login shell on the very same system, purely because it never sourced the interactive-only override files.
# Compare interactive vs non-interactive umask directly on the same system
umask # interactive shell value
echo 'umask' | at now + 1 minute 2>&1 # scheduled job's inherited value, for comparison
umask With NFS and Network Filesystems
A subtlety worth flagging for anyone managing shared network storage: umask is applied by the client-side process creating the file, not by the NFS server — meaning the permission behavior a user sees on a network-mounted share depends on the umask active in their own shell session on the client machine, not on any server-side umask configuration at all. This trips people up when they’ve configured what they believe is a consistent permission policy on the NFS server itself, only to find files still arriving with inconsistent permissions purely because different client machines (or different users on the same client) have different active umask values.
The practical fix, when consistent permissions genuinely matter on shared network storage, is usually a combination of setgid directories (to fix group ownership) plus enforcing a consistent umask policy across every client that mounts the share, rather than trying to control it from the server side, which the umask mechanism simply doesn’t support.
Troubleshooting
Need to verify what umask a running process actually has:
cat /proc/PID/status | grep Umask
Confirm current session umask before running something sensitive:
umask
umask -S
Testing umask behavior safely without touching real files — exactly what I did to verify this article: create in /tmp, check the result, then clean up:
umask 077
touch /tmp/test_permission_check
ls -l /tmp/test_permission_check
rm /tmp/test_permission_check
Summary
umask decides the default permissions of every newly created file and directory by subtracting itself from a base of 666 for files and 777 for directories — never adding permissions, only removing them. The common defaults are 022 for general use, 027 for group-restricted environments, and 077 for fully private contexts like SSH keys and credential files. I confirmed the full behavior directly: octal and symbolic display, file creation under 077, and directory creation under 022 all matched documented behavior exactly, with no surprises.
