Chmod Calculator

755 is rwxr-xr-x, and the three digits are just read-write-execute added up for the owner, the group and everyone else. The arithmetic is trivial; remembering which digit does what at 2am is not.

Leave this blank to use the checkboxes instead. Both octal and rwx notation are accepted, with or without the leading file-type character.
Chmod Calculator — Octal 755, Symbolic rwxr-xr-x and the Special BitsBuildFigure

One digit, three bits

A permission digit is read (4) plus write (2) plus execute (1), so it runs 0 through 7 and every value has exactly one meaning. 7 is rwx, 6 is rw-, 5 is r-x, 4 is r--, 0 is nothing. Three digits cover the owner, the group and everyone else, in that order, which is why 755 reads as "owner does everything, everyone else reads and runs". A fourth digit in front is the special bits: setuid 4, setgid 2, sticky 1. The leading character in ls -l output — d, -, l — is the file type and is not part of the mode at all.

On a directory, x does not mean execute

This is the single most common source of confusion, and it is worth stating precisely.

BitOn a fileOn a directory
rRead the contentsList the entry names
wModify the contentsCreate, delete and rename entries inside
xRun itTraverse it — resolve a path through it, cd into it, stat what is inside

Two consequences fall out of that table. A directory with r and no x lets you see names you cannot open. A directory with x and no r lets you open a file whose exact name you already know while ls returns nothing. And the permission that governs deleting a file lives on the directory, not the file — the write bit on report.txt has no say in whether report.txt can be removed. That is why a read-only file in a writable directory still disappears when someone runs rm.

It is also why a 403 from a web server so often survives a chmod 644 on the file itself. If any directory along the path is missing its x bit for the server's user, the server never reaches the file to be refused by it. Walk the path from the top with namei -l /var/www/html/index.html and the missing bit shows up immediately.

Why 777 is not the fix

When an upload fails or a log will not write, 777 makes the error go away in one command, and that is exactly the problem: it removes the check instead of satisfying it. The result is a file that every local account, every cron job and every process that has been talked into running attacker-supplied code can rewrite. On shared hosting that includes other customers. In a container it includes anything that broke out of a neighbouring process.

The actual cause is nearly always ownership. If the web server runs as www-data and the files belong to your login account, the answer is chown -R www-data:www-data on the directory the application writes to, with 755 on directories and 644 on files. If several accounts genuinely need write access, put them in a shared group, set 775 and 664, and add the setgid bit on the directory so new files keep the group. That is what setgid is for.

If you do use 777 as a diagnostic — and sometimes it is the fastest way to confirm that permissions really are the problem — write down where, and put it back the same day.

The three special bits

setuid makes a binary run as its owner rather than as the caller. /usr/bin/passwd needs it because an ordinary user has to modify /etc/shadow. On anything you wrote yourself it is a liability: every command the program shells out to, every path it trusts, every environment variable it reads becomes an attack surface at the owner's privilege level. Linux ignores setuid on #! scripts entirely, which surprises people who set it and assume it worked.

setgid on a binary is the group equivalent and is uncommon. On a directory it is genuinely useful: new files inside inherit the directory's group instead of the creator's primary group, which is what keeps a shared project directory consistent without anyone remembering to run chgrp.

sticky only matters on directories. In a world-writable directory it restricts deletion and renaming to the owner of each entry. /tmp is 1777 for precisely this reason — everyone needs to write there, nobody should be able to remove someone else's socket.

In the symbolic display, a lowercase s or t means the special bit and the execute bit are both set. An uppercase S or T means the special bit is set and the execute bit is not, which is almost always an accident and almost always inert.

umask, and why chmod -R needs a capital X

New files are created 666 minus the umask, new directories 777 minus it — an AND NOT, strictly. A umask of 022 gives you 644 files and 755 directories, which is the default nearly everywhere and the reason your new files are never executable. 077 gives 600 and 700. 002 gives 664 and 775 and belongs on a shared group setup. Run umask with no arguments to see the current value; it applies only at creation time and changes nothing that already exists.

That difference between files and directories is what makes chmod -R 755 a bad habit — it marks every text file, image and config in the tree executable. Use chmod -R u=rwX,go=rX instead. The capital X adds the execute bit to directories and to files that already had it somewhere, and leaves everything else alone. It is one character and it is the difference between fixing a tree and having to fix it twice.

Questions people ask

What is the difference between 0644 and 644?

Nothing. The leading zero is either octal notation carried over from C, or an explicit statement that no special bits are set — either way it is the same mode. A leading digit other than zero is meaningful: 4755 is setuid plus 755, 2775 is setgid plus 775, 1777 is sticky plus 777. Some tools print four digits always and some print three, which is the only reason it comes up.

Why does SSH refuse to use my private key?

Because the key is group or world readable. OpenSSH checks the mode of the private key and of ~/.ssh itself, and refuses rather than warns, on the reasoning that a key anyone on the box can read is already compromised. Set the key to 600 and the directory to 700. The same check applies to the file when it arrives from a git checkout or an unzip, both of which will happily hand you a 644 key.

Does any of this apply on Windows?

Not natively. NTFS uses ACLs, which are more expressive than nine bits and do not map onto an octal mode. Inside WSL, a container, or a Git Bash session against a Linux host, ordinary POSIX permissions apply. Git itself tracks exactly one bit — a blob is stored as 100644 or 100755 — so an executable bit survives a clone and nothing else does, which is why a script checked out on a fresh machine so often needs chmod +x.

I set the mode correctly and access is still denied.

Work outward. Check the execute bit on every directory in the path, check the owner and group actually match the process identity you think they do, then check whether something above the file system is refusing: SELinux or AppArmor, a mount flag such as noexec or ro, an ACL that ls flags with a trailing +, or an immutable attribute visible in lsattr. Ordinary permissions are the first layer to check and rarely the last.

Related