What is umask — and why 666 minus 033 isn't 633

Here's a puzzle. You create a file with touch notes.txt. You don't specify any permissions. You check — the file has 644: you can read and write, everyone else can only read.
Who decided that? You didn't ask for anything.
A tiny setting almost nobody knows about decided it. It's called umask. And it has a catch that trips up even people who know it: it isn't subtraction.
What umask is
umask is a mask that takes permissions away from every new file. It lives in every process: your terminal, a Python script, a web server. Every file a process creates goes through this mask.
You can see yours with one command:
umask
# 0022
Most often you'll see 0022 or 0002. The leading zero doesn't matter; look at the last three digits.
How it works
First, a quick reminder about permission digits. Each digit is a sum: 4 = read, 2 = write, 1 = execute. Three digits — for the owner, the group, and everyone else. 644 means: owner 4+2, group 4, others 4.
Now the mechanics. When a program creates a file, it usually asks for the maximum:
- for a regular file —
666(everyone reads and writes); - for a folder —
777(everything for everyone, including entering the folder).
Then umask crosses out its bits from that maximum. With mask 022, "write" is crossed out for the group and for others. You get 644 for a file and 755 for a folder.
Notice: for a file the maximum is 666, not 777. A new file never gets execute permission, whatever the mask. That's why your fresh script answers Permission denied until you say chmod +x script.sh. It's not a bug, it's protection: the system doesn't want any downloaded file to become a program by itself.
Why it isn't subtraction
Here's the catch. It looks like umask is just subtracted: 666 − 022 = 644. Checks out! Let's try another mask:
umask 033
touch a.txt
stat -c '%a' a.txt
# 644
By arithmetic it should be 666 − 033 = 633. The system gave 644.
The mask doesn't subtract — it turns bits off. A 3 in the mask means "write" (2) + "execute" (1). The file doesn't have "execute" anyway. You can't cross out what isn't there — only "write" goes away. From 6 you're left with 4.
A folder does have "execute", so there the arithmetic matches: 777 with mask 033 gives 744.
Remember the rule: the mask says which permissions to definitely switch off, not how much to subtract. Don't do column arithmetic — think in bits: 4, 2, 1, on or off.
Why you should care
OK, the mask works quietly. When does it become your problem?
1. Secrets. You save an API key in .env or write a token to a file from a script. With mask 022 the file gets 644 — any user on the server can read it. You can fix it later with chmod 600, but for a few moments the file is open. It's more reliable to lock it from birth:
(umask 077; echo "$TOKEN" > secret.txt)
# permissions 600: only you
The parentheses here are a subshell. The mask changes only inside it and doesn't touch the rest of your terminal.
2. A shared folder on a server. You and a teammate deploy to the same folder. They create files, and you can't edit them — Permission denied. Often the culprit is mask 022: the group isn't allowed to write. Mask 002 keeps write for the group, and the shared work stops breaking.
3. Code is under the mask too. In Node, fs.writeFileSync(path, data, { mode: 0o666 }) won't give you 666 — the process mask still applies. In Python, os.makedirs(path, mode=0o777) is the same. If permissions came out "wrong", check the process umask, not the code.
4. Services. A program running as a daemon has its own mask, not yours. In systemd you set it with UMask=0077 in the [Service] section.
How to change umask
- Just for now:
umask 077— until the end of this terminal session. - Permanently for you: add
umask 027to~/.bashrcor~/.zshrc. That's an ordinary dotfile with shell settings. - For one command: parentheses, like in the secret example above.
A handy strictness scale: 002 — for team work, 022 — normal mode, 077 — everything private.
Are umask and chmod the same thing?
No. chmod changes permissions on a file that already exists. umask sets default permissions for files that don't exist yet. One is a repair, the other is a rule for new buildings.
Why does umask 0022 have four digits?
The first digit is for special bits (setuid, setgid, sticky). The mask almost never touches them, so it's zero. Look at the last three.
Does umask affect files from git clone?
Yes. Git creates files like any process, and the mask applies. The exception is execute permission: if a script was executable in the repo, git restores it.
Short story-lessons, an agent simulator and daily practice — in our mobile app. Free.





