Linux File Permissions — Read, Write, Execute Without Tears
A clear walkthrough of Linux file permissions. Read the funny rwx- letters, change them safely with chmod, fix "permission denied" errors with confidence.
Key takeaways
- A clear walkthrough of Linux file permissions.
- Read the funny rwx- letters, change them safely with chmod, fix "permission denied" errors with confidence.
On this page
Linux File Permissions: Read, Write, Execute Without Tears#
By the end of this post you'll be able to read any ls -l output at a glance, change permissions safely with chmod, and debug "permission denied" errors without guessing. About 20 minutes. You'll need a Linux or macOS terminal — both behave the same for the purposes of this tutorial.
The model#
Every file in Linux has three classes of users it cares about:
- Owner (the user who owns the file)
- Group (a named group; many files belong to a group like
stafforwheel) - Other (everyone else)
For each class, three permissions can be granted:
- r — read
- w — write
- x — execute (run as a program, or for directories: enter and list)
That's the whole model. Owner/group/other × read/write/execute = nine bits per file.
Step 1: Read ls -l output#
Run:
ls -l
You'll see lines like:
-rw-r--r-- 1 alice staff 1.2K Apr 28 10:15 notes.txt
drwxr-xr-x 3 alice staff 96B Apr 28 10:15 projects
-rwxr-xr-x 1 alice staff 2.4K Apr 28 10:15 deploy.sh
The first column is the permission string. Decode it left to right:
-rwxr-xr-x
^|||++|+++
| | | |
| | | other: r-x (read, no write, execute)
| | group: r-x (read, no write, execute)
| owner: rwx (read, write, execute)
file type: - (regular file; "d" = directory, "l" = symlink)
So -rwxr-xr-x means: regular file, owner can do everything, group and other can read and execute but not write.
Practice:
-rw-r--r--→ owner can read+write, group and other can only readdrwx------→ directory, only owner has access (private dir)-rwxrwxrwx→ file, anyone can do anything (almost always wrong)
Once you can read these in your sleep, the rest is easy.
Step 2: Octal notation#
That -rwxr-xr-x string can be written as a 3-digit number: 755. This is what people mean when they say "chmod 755."
The mapping:
r = 4
w = 2
x = 1
Add them up per class:
rwx= 4+2+1 = 7r-x= 4+0+1 = 5r--= 4+0+0 = 4---= 0+0+0 = 0
So rwxr-xr-x = 7-5-5 = 755. The three digits are owner-group-other.
Common ones to memorize:
- 755 —
rwxr-xr-x— executable scripts, public dirs (default for many) - 644 —
rw-r--r--— regular files (default for most) - 600 —
rw-------— private files (SSH keys, secrets) - 700 —
rwx------— private dirs - 777 —
rwxrwxrwx— almost always wrong; means anyone can do anything
That's 90% of permissions you'll see in practice.
Step 3: Change permissions with chmod#
Two ways: numeric or symbolic.
Numeric is what scripts use:
chmod 644 notes.txt # owner rw, group/other r
chmod 755 deploy.sh # owner rwx, group/other rx
chmod 600 ~/.ssh/id_rsa # private (SSH requires this for keys)
Symbolic is more readable for one-off changes:
chmod +x deploy.sh # add execute for everyone
chmod u+w notes.txt # add write for owner (u = user/owner)
chmod g-w notes.txt # remove write from group
chmod o-rwx secrets.txt # remove all permissions from "other"
chmod a+r public.txt # add read for all (a = all classes)
Try it:
echo "test" > demo.txt
ls -l demo.txt # default 644
chmod 600 demo.txt
ls -l demo.txt # now -rw-------
chmod a+x demo.txt
ls -l demo.txt # now -rwx--x--x (oddly mixed)
The ls -l output should change each time, reflecting your new permissions.
Step 4: Change ownership with chown#
chmod changes permissions. chown changes the owner and/or group:
sudo chown bob notes.txt # change owner to bob
sudo chown bob:developers notes.txt # owner=bob, group=developers
sudo chown :developers notes.txt # change only the group
Most operations need sudo because changing ownership is a privileged operation.
For directories with many files, -R (recursive) does the whole tree:
sudo chown -R bob:developers /var/www/myapp
Use -R carefully — it changes everything inside the directory.
Step 5: Directory permissions are subtler#
A common confusion: what does "execute" mean on a directory?
For a directory, x means "you're allowed to enter it and access files inside." Without x, even if you have r, you can list filenames but can't actually open any of them.
mkdir test_dir
echo "hello" > test_dir/file.txt
chmod 644 test_dir # rw on dir, but no x
cat test_dir/file.txt # permission denied — no x means no enter
chmod 755 test_dir
cat test_dir/file.txt # works now
Practical rule: directories you want to access need x for whoever's accessing them. Standard public dirs are 755 (everyone can enter, only owner can write). Private dirs are 700.
Step 6: Debug "permission denied"#
When a command fails with permission denied, ask three questions in order:
- Who am I? —
whoami. The current user is the one whose permissions are being checked. - Who owns the file? —
ls -l <file>. If owner is someone else and you're not in the group, only "other" permissions apply. - What permissions are set? — same
ls -l. Compare what you have against what you need.
Example: trying to write to a file you don't own:
$ whoami
alice
$ ls -l /var/log/syslog
-rw-r----- 1 root adm 12k Apr 28 10:15 /var/log/syslog
Owner is root. Group is adm. Other has no permission. Alice is not root and (probably) not in adm — so she falls into "other" and has no read access. Solution: sudo cat /var/log/syslog, or sudo usermod -aG adm alice and re-login to add her to the group.
Common mistakes#
chmod 777 to fix problems. Setting 777 does work — anyone can do anything — but is almost never the right answer. It makes the file world-writable, which is a security disaster for anything sensitive. Find the right specific permissions instead.
Recursive chmod on the wrong directory. chmod -R 777 / (yes, people have done this) is the operating-system-equivalent of digging up your foundations. Always confirm the path before recursive chmod.
Confusing chmod and chown. chmod changes permissions, chown changes ownership. You'll mix them up the first 10 times — that's normal.
Thinking root bypasses permissions. Root doesn't get blocked by file permissions, but it still gets blocked by SELinux, AppArmor, and immutable bits (chattr +i). If sudo doesn't help, those are the next things to check.
Setting the wrong permissions on ~/.ssh. SSH refuses to use keys with too-permissive permissions. ~/.ssh should be 700, files inside should be 600 or 644. SSH will warn you loudly when this is wrong.
What to read next#
You've got the model. The next levels:
- SSH tutorial: keys, config, and working remotely — where file permissions matter most
- Linux security hardening — the broader hardening checklist for production servers
- Linux process management and monitoring — what's running, who owns it, why
Linux file permissions look intimidating until they click. Once they do, "permission denied" stops being a mystery and starts being a 30-second debugging task. Every Linux user goes through this transition; the tutorial just makes it faster.
Get the DevOps Troubleshooting Cheat Sheet
Subscribe and get our free one-page reference for the errors that eat an afternoon — CrashLoopBackOff, OOMKilled, Terraform state locks, and more — plus new guides as we publish them.
Kubernetes 101 — Pods, Deployments, and Services Explained
Run your first three Kubernetes objects — Pod, Deployment, Service — on a local cluster, then understand why each one exists and how they fit together.
Prompt Engineering Basics — From "Help Me" to Working Prompts
A hands-on intro to prompt engineering. Learn the four levers (role, format, examples, constraints) and watch a vague prompt turn into a reliable one.
More from Linux
Explore more articles in this category
ext4 vs XFS vs Btrfs: Choosing a Filesystem for a Server
The default filesystem your distro picks is not always the right one for your workload. Here is what actually differs and when each one wins.
journald Log Management: Retention, Filtering, and Forwarding
journald is the default log sink on every systemd distro, and most of it runs on defaults nobody chose. Here is how to actually control it.
DNS Troubleshooting on Linux: A Systematic Approach
\"It's always DNS\" is a joke because the failure modes are so scattered: resolver config, caching, search domains, split DNS. Here is where to actually look.
You might have missed
Evergreen posts worth revisiting.