Skip to main content
Linux File Permissions — Read, Write, Execute Without Tears

Linux File Permissions — Read, Write, Execute Without Tears

KU
• 6 min read•Updated •54 views

A clear walkthrough of Linux file permissions. Read the funny rwx- letters, change them safely with chmod, fix "permission denied" errors with confidence.

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 staff or wheel)
  • 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:

bash.bash
ls -l

You'll see lines like:

code
-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:

code
-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 read
  • drwx------ → 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:

code
r = 4
w = 2
x = 1

Add them up per class:

  • rwx = 4+2+1 = 7
  • r-x = 4+0+1 = 5
  • r-- = 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:

bash.bash
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:

bash.bash
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:

bash.bash
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:

bash.bash
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:

bash.bash
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.

bash.bash
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:

  1. Who am I? — whoami. The current user is the one whose permissions are being checked.
  2. Who owns the file? — ls -l <file>. If owner is someone else and you're not in the group, only "other" permissions apply.
  3. 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:

code
$ 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.

You've got the model. The next levels:

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.

Explore topics:Linux
React
Share this post
KU

Kiril Urbonas

AI Engineer

560 articles
View all articles by Kiril Urbonas

You might have missed

Evergreen posts worth revisiting.