Skip to content
OneKitly

How Unix File Permissions Work: Reading 755 Without Guessing

Published 4/24/2026 · 7 min read · Developer tools

Daniel Okonkwo

Daniel OkonkwoFront-end developer and tech writer at OneKitly

Web performance · File formats

Checked against 2 sources

View profile
In short

A Unix permission mode is three octal digits: one for the file's owner, one for its group, one for everyone else. Inside a digit, read is 4, write is 2 and execute is 1, and you add them — 7 is rwx, 6 is rw-, 5 is r-x, 4 is r--. So 755 is rwxr-xr-x: the owner may read, write and execute, everyone else may read and execute. On a regular file the execute bit lets the kernel run it. On a directory it means something else entirely — it grants the right to traverse the directory, that is to reach an entry by name. Read on a directory only lets you list the names; without execute you cannot open, stat or enter any of them. An optional fourth digit in front carries setuid (4000), setgid (2000) and the sticky bit (1000), so /tmp is 1777.

Read is 4, write is 2, execute is 1, and each of the three digits describes a different party. The part most explanations get wrong is what the execute bit does on a directory — it grants traversal, not the right to run anything.

Three digits, three parties, and only one of them applies

In `ls -l` output the first character is the type — a dash for a regular file, d for a directory, l for a symbolic link — and the next nine are three groups of three: owner, group, other. What surprises people is that these are not cumulative. The kernel picks the first class you belong to and stops there. If you own a file whose mode is 477, you get r-- and nothing more, even though the group and other bits are wide open, because the owner class matched first and the rest is never consulted.

There are two ways to write a change and they are not equivalent. Octal is absolute: `chmod 644 notes.txt` sets the whole mode and wipes whatever was there before. Symbolic is relative: `chmod u+x script.sh` adds one bit and leaves the other eight untouched. In a deployment script you almost always want the octal form, because it produces the same end state whatever the file looked like when it arrived.

On a directory, the execute bit is a completely different right

Nothing is ever executed by giving a directory the x bit. On a directory that bit is search permission: it lets a process resolve a name inside the directory and reach the thing behind it. The split is easy to see. Set a directory to 400 and `ls` will happily print the names it contains, but every stat fails and `cat dir/file` is refused — you can see the labels and touch nothing. Set it to 100 instead and the reverse happens: you cannot list anything, yet if you already know the exact path you can open the file. That asymmetry is why a home directory set to 711 works — other users can reach ~/public_html without being able to enumerate what else is in there.

The same logic explains a result that looks like a bug. Deleting a file is not a modification of the file — it is a modification of the directory that lists it. So the permission that decides whether a file can be removed is write plus execute on the containing directory, and the file's own mode is irrelevant. A file at 444 sitting in a directory at 777 can be deleted by anyone on the machine. That is exactly the hole the sticky bit was invented to plug, which is why /tmp is 1777 rather than 0777.

The fourth digit, and why umask is not a permission

Three special bits sit in an optional leading digit. Setuid is 4000: on an executable binary it runs with the owner's identity, which is how passwd can edit a file you cannot. On Linux it is silently ignored on interpreted scripts, and it has no meaning at all on a directory. Setgid is 2000: on a binary it does the same for the group, and on a directory it does something far more useful — new entries inherit the directory's group instead of the creator's, and new subdirectories inherit the setgid bit too, which is the standard way to keep a shared project tree consistent. Sticky is 1000: on a directory it restricts deleting and renaming an entry to the entry's owner, the directory's owner, or root.

Umask is the piece people most often invert. It is not the permission new files get — it is a mask of bits to clear from what the creating program asked for. Programs ask for 666 for a file and 777 for a directory, and every bit set in the umask is switched off. With the common umask 022 you therefore get 644 for files and 755 for directories. And it clears rather than subtracts: umask 023 still produces 644 on a new file, not 643, because the file never requested the execute bit in the first place and there is nothing to take away. One more relative: `chmod +x` with no class letter is not the same as `chmod a+x`, because the bare form also honours your umask — under umask 077 it grants execute to the owner alone.

What each octal digit means — and how it changes on a directory
DigitSymbolicOn a fileOn a directory
0---No access at allNo access at all
1--xMay be run by the kernelTraverse only: reach an entry whose exact name you already know, but never list the contents
2-w-May be modified or truncatedUseless on its own — creating or deleting an entry also needs the execute bit
3-wxModify and run, but not readCreate, delete and rename entries without being able to list them — a drop box
4r--May be readList the names only — every attempt to stat or open an entry is refused
5r-xRead and runList and traverse — the normal setting for a directory others should browse
6rw-Read and modify — the default for a new fileList the names, reach nothing, and still create nothing — write without execute is dead weight
7rwxRead, modify and runFull control: list, traverse, create, rename and delete entries
Unix Permission Calculator (chmod)Convert between octal, symbolic and rwx Unix file permissions, with special bits and a chmod command.Try the tool

Frequently asked questions

Why is chmod 777 the wrong fix?
It gives write access to every account on the machine, including whatever your web server or a compromised process runs as, and world-writable code is code anyone can replace. It also usually misses the real cause, which is more often wrong ownership or a missing execute bit on a parent directory than a permission that is too narrow. Some software refuses to cooperate with it outright: OpenSSH ignores a private key or an authorized_keys file that is group- or world-writable.
Does chmod 755 make a script runnable?
It grants permission to try, which is not the same as making it work. A text file also needs a shebang line naming an interpreter that exists, or the kernel has nothing to hand it to. Two other things override the mode entirely: a filesystem mounted with the noexec option refuses to run anything on it whatever the bits say, and every directory on the path to the file needs its own execute bit before the file can even be reached.
Why can someone delete a file I set to read-only?
Because deletion is a change to the directory, not to the file. The kernel checks write and execute on the directory that holds the name, and never looks at the file's own mode. To stop it you either tighten the directory or set the sticky bit on it, which limits deleting and renaming to the entry's owner, the directory's owner and root — the reason a shared /tmp is 1777.

Articles you may find interesting

All guides

Related tools

Sources

Spotted a mistake in this article?