Linux Permissions Explained Visually
What Does -rw-r--r-- Actually Mean?
Every time you run ls -l on a Linux system, a string of characters stares back at you. Most people learn to ignore it. The engineers who truly understand Linux permissions don't — and the difference shows up the moment something breaks in production. This guide breaks down the full permissions model visually, step by step, so it sticks the first time.
Reading ls -l — A Labelled Breakdown
Run ls -l on a typical file and you'll see something like this:
$ ls -l /etc/nginx/nginx.conf
-rw-r--r-- 1 root root 2957 Jun 10 09:14 /etc/nginx/nginx.conf
Let's label every field:
- rw- r-- r-- 1 root root 2957 Jun 10 09:14 nginx.conf
T OWN GRP OTH lnk user group size date name
T = type (- file, d dir, l symlink)
OWN/GRP/OTH = the three permission triplets
The ten-character string is made of one type character followed by three permission triplets: owner, group, other. Each triplet is always in the order r (read), w (write), x (execute). A dash (-) means the permission is absent.
The Three Permissions — on a File vs a Directory
Here is where most tutorials lose people. The meaning of r, w, and x changes depending on whether the target is a file or a directory.
| Permission | On a File | On a Directory |
|---|---|---|
r (read, 4) | Read the file's contents | List the directory's contents (ls) |
w (write, 2) | Modify the file's contents | Create, rename, or delete entries inside it |
x (execute, 1) | Run the file as a programme | Traverse (enter) the directory (cd) |
The execute-on-directory point is the most commonly misunderstood in all of Linux. You can have r on a directory (you can see filenames with ls) but without x you cannot cd into it or access anything inside. The execute bit on a directory means "permission to pass through".
Owner, Group, Other
Linux assigns every file three audiences: the owner (the user who owns it), the group (a named group of users), and other (everyone else). Permission checks happen in order — owner first, then group, then other. If you are the owner, Linux applies the owner triplet and stops; it does not also check group or other.
Octal vs Symbolic chmod
Symbolic mode
# Add execute for the owner
chmod u+x deploy.sh
# Remove write from group and other
chmod go-w secrets.txt
# Set exact permissions: owner=rwx, group=rx, other=nothing
chmod u=rwx,g=rx,o= script.sh
The letters are: u = user/owner, g = group, o = other, a = all three.
Octal mode
Each permission has a numeric value: r=4, w=2, x=1. Add them together for each triplet.
| Octal | Binary | Permissions |
|---|---|---|
| 7 | 111 | rwx |
| 6 | 110 | rw- |
| 5 | 101 | r-x |
| 4 | 100 | r-- |
| 0 | 000 | --- |
So chmod 644 file.txt means: owner=rw (6), group=r (4), other=r (4).
chmod 644 index.html # public file: owner rw, everyone else read
chmod 755 deploy.sh # script: owner all, group/other read+execute
chmod 600 ~/.ssh/id_rsa # private key: only the owner can read it
Use the chmod calculator to convert between octal and symbolic interactively.
chown — Changing Ownership
chown www-data file.html # change owner
chown www-data:www-data /var/www/html # change owner AND group
chown -R deploy:deploy /opt/app # recursively
Only root (or a process with CAP_CHOWN) can change file ownership.
umask — The Default Permission Filter
When a new file or directory is created, its starting permissions are set by the process's umask, which removes permissions from a base. New files start at 666, new directories at 777. With the common default umask of 022:
File: 666 - 022 = 644 → rw-r--r--
Directory: 777 - 022 = 755 → rwxr-xr-x
umask # check current umask
umask 027 # stricter: new files 640, new dirs 750
For a live calculator, see the umask calculator.
Recursive chmod and the Capital-X Trick
Recursive changes are dangerous if you apply the same chmod to both files and directories:
# WRONG: gives execute to data files — makes them "runnable"
chmod -R 755 /var/www/html
The correct approach uses capital X, which adds execute only to directories (or files that already have execute set):
# CORRECT: files get 644, directories get 755
chmod -R u=rwX,go=rX /var/www/html
Capital X is one of the most underused flags in day-to-day Linux work.
Special Permission Bits — setuid, setgid, Sticky
| Bit | Octal | On Files | On Directories |
|---|---|---|---|
| setuid | 4000 | Run as the file's owner (e.g. passwd runs as root) | (rarely used) |
| setgid | 2000 | Run as the file's group | New files inherit the directory's group |
| sticky | 1000 | (legacy, ignored) | Only the file's owner can delete it (e.g. /tmp) |
ls -l /usr/bin/passwd # -rwsr-xr-x — the 's' is setuid
ls -ld /tmp # drwxrwxrwt — the 't' is the sticky bit
chmod g+s /srv/shared # setgid on a shared project directory
For deeper coverage, see the full concept guide: Linux file permissions.
Real-World Example: The nginx 403 Forbidden
The single most common permissions bug in web deployments:
# nginx returns 403 Forbidden. The file looks fine:
ls -l /var/www/myapp/index.html
# -rw-r--r-- 1 deploy deploy 4096 index.html
# But check the directory:
ls -ld /var/www/myapp/
# drw------- 3 deploy deploy 4096 /var/www/myapp/
Nginx runs as www-data. The directory is 700 — only deploy can traverse it. www-data hits a wall and nginx returns 403.
chmod o+x /var/www/myapp/ # grant traverse to other
# (a missing DIRECTORY execute bit is almost always the culprit)
Quick Reference
600 rw------- Private files (SSH keys, .env)
644 rw-r--r-- Public files (web assets, configs)
700 rwx------ Private scripts or directories
750 rwxr-x--- Shared dirs (owner full, group read/exec)
755 rwxr-xr-x Public scripts and directories
777 rwxrwxrwx AVOID — full open (debug only)
Keep Learning
Linux permissions look small but cascade into nearly every area of systems work. The best way to build fluency is to encounter permissions problems regularly and reason through them. The Linux track covers permissions in the broader context of the filesystem and processes, and the daily challenge keeps your instincts sharp. Ready to go deeper? Join the ShellQuest waitlist for early access to interactive labs where you practise chmod, chown, and umask inside a real simulated terminal — with instant feedback and no server to break.
Liked this? ShellQuest turns these mental models into puzzles and labs you can actually practise.
Join the waitlist