# Linux File Permissions — Read, Write, Execute Without Tears

URL: https://www.devopsness.com/blog/linux-file-permissions-explained
Author: Kiril Urbonas
Published: 2026-04-29
Updated: 2026-05-14
Categories: Linux
Tags: Linux, Permissions, Security, Tutorial, Beginner

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

---
# 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 `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
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 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:

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

```
$ 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](/blog/ssh-tutorial-keys-config-remote-work) — where file permissions matter most
- [Linux security hardening](/blog/linux-security-hardening-protecting-system) — the broader hardening checklist for production servers
- [Linux process management and monitoring](/blog/process-management-monitoring-linux) — 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.

