Linux File Permissions and Ownership Explained

Tested on RHEL 10.2 (Coughlan)
Package coreutils 9.5-8.el10_2
bash 5.2.26-6.el10
Applies to Ubuntu, Debian, Kali Linux, Linux Mint, Pop!_OS, Raspberry Pi OS, elementary OS, Zorin OS, Parrot OS, MX Linux, RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora, Arch Linux
Privilege Normal user for most examples; sudo for chown, chgrp, and privileged paths
Scope Owner, group, and other classes; read, write, and execute on files versus directories; ls -l interpretation; chmod symbolic and octal modes; chown and chgrp; recursive find patterns; brief umask, SUID, SGID, and sticky bit; permission denied diagnosis. Does not cover ACL administration, full SELinux policy, or MAC hardening.
Related guides Linux command line
Linux filesystem hierarchy
Redirection and pipes
Edit text files
RHCSA tutorial

Every path on Linux carries an owner, a group, and a mode that says which users may read, write, or execute it. The confusing part is not memorizing rwx strings—it is that the same letter means something different on a directory than on a file. This guide walks through that distinction, then shows how to change modes and ownership without reaching for chmod 777 as a default fix.


How Linux File Permissions Work

Linux classifies access into three permission classes and three operation types.

Class Who it applies to
Owner (u) The user ID stored on the file
Group (g) Members of the file's group ID
Other (o) Everyone who is not owner and not in that group
Permission On a regular file On a directory
Read (r) Open and read contents List entry names (ls)
Write (w) Change file contents Create, rename, or delete entries (with execute)
Execute (x) Run as a program or script Traverse the directory (cd, access paths inside)

ls -l shows the mode string, owner, and group for each path.

bash
ls -l /etc/hosts /bin/ls

Sample output:

output
-rwxr-xr-x. 1 root root 141160 Jun  2 05:30 /bin/ls
-rw-r--r--. 1 root root    454 Aug  7 21:57 /etc/hosts

/bin/ls is executable by owner, group, and other. /etc/hosts is world-readable but not executable—typical for a static text file.


Linux Permissions Quick Reference

Keep these tables nearby while you practice. They are patterns, not universal security policy.

Permission values

Permission Value
Read (r) 4
Write (w) 2
Execute (x) 1

Add the bits in each triplet to build octal modes. Owner, group, and other each contribute one digit.

Common modes

Mode Typical meaning
644 Owner read/write; others read
600 Owner read/write only
755 Owner full; others read and execute
700 Owner full only
IMPORTANT
These modes are examples for learning—not a checklist of “correct” production permissions. A private key might need 600, a public HTML file might need 644, and a shared upload directory might need a dedicated group plus sticky bit. Match the mode to the data and the users who must reach it.

Read Permission Strings from ls -l

The first ten characters describe file type and mode bits. GNU ls may add another character afterward: . commonly indicates an SELinux security context on RHEL, while + indicates additional access controls such as an ACL.

text
-rwxr-x---

Read it from left to right:

  • First character: file type (- file, d directory, l symlink)
  • Characters 2–4: owner rwx
  • Characters 5–7: group r-x
  • Characters 8–10: other ---
  • Optional 11th character on GNU ls: . for SELinux context on RHEL, or + for ACLs and similar extensions

stat prints the numeric mode when you want digits without mental arithmetic.

bash
stat -c '%a %n' /etc/hosts

Sample output:

output
644 /etc/hosts

644 maps to rw-r--r--: owner read+write (4+2), group read (4), other read (4).


Prepare the permission lab

The directory and su - student examples below use paths under /tmp/perm-lab. Run this block once on a clean VM as root before the first permission test.

Confirm a normal test account exists. On many classroom images student is already present; create it when id fails.

bash
id student

Sample output:

output
uid=1001(student) gid=1001(student) groups=1001(student)

If the account is missing, add it:

bash
useradd -m student

Remove any prior lab tree and create directories and sample files.

bash
rm -rf /tmp/perm-lab
bash
mkdir -p /tmp/perm-lab/{dir-r,dir-x,dir-rx,private,shared,web}
bash
echo test > /tmp/perm-lab/dir-r/test
bash
echo 'secret' > /tmp/perm-lab/private/secret.conf
bash
echo 'hidden content' > /tmp/perm-lab/dir-x/hidden.txt
bash
echo 'echo hello' > /tmp/perm-lab/runme.sh

Set initial modes and ownership so later chmod, chown, and chgrp steps start from a known state.

bash
chmod 755 /tmp/perm-lab/runme.sh /tmp/perm-lab/private
bash
chmod 1777 /tmp/perm-lab/shared
bash
chown root:root /tmp/perm-lab/private/secret.conf
bash
chmod 600 /tmp/perm-lab/private/secret.conf

Verify the tree before you change modes in the demos.

bash
ls -la /tmp/perm-lab/

Sample output:

output
total 8
drwxr-xr-x.  8 root root  102 Aug  7 23:26 .
drwxrwxrwt. 29 root root 4096 Aug  7 23:26 ..
drwxr-xr-x.  2 root root   18 Aug  7 23:26 dir-r
drwxr-xr-x.  2 root root    6 Aug  7 23:26 dir-rx
drwxr-xr-x.  2 root root   24 Aug  7 23:26 dir-x
drwxr-xr-x.  2 root root   25 Aug  7 23:26 private
-rwxr-xr-x.  1 root root   11 Aug  7 23:26 runme.sh
drwxrwxrwt.  2 root root    6 Aug  7 23:26 shared
drwxr-xr-x.  2 root root    6 Aug  7 23:26 web

runme.sh starts as 755 owned by root:root. The symbolic chmod section below changes its mode; the chgrp section later sets group student.


File Permissions vs Directory Permissions

This is the section most permission guides rush past. On a file, the bits describe the file body. On a directory, they describe the directory inode—the catalog of names inside it.

For a regular file:

  • r — read bytes from the file
  • w — change bytes in the file
  • x — execute the file as a program (scripts need this too)

For a directory:

  • r — list names in the directory (ls can show filenames)
  • w — add, rename, or remove entries (still needs execute on that directory)
  • x — traverse the directory; required to reach paths inside or to cd into it

Directory with read but no execute

Create a directory with read for everyone but no execute bit.

bash
chmod 644 /tmp/perm-lab/dir-r
bash
ls -ld /tmp/perm-lab/dir-r

Sample output:

output
drw-r--r--. 2 root root 18 Aug  7 23:17 /tmp/perm-lab/dir-r

A non-root user can still list names when read is set.

bash
su - student -c 'ls /tmp/perm-lab/dir-r'

Sample output:

output
test

Opening a file inside fails without traverse permission on the directory.

bash
su - student -c 'cat /tmp/perm-lab/dir-r/test'

Sample output:

output
cat: /tmp/perm-lab/dir-r/test: Permission denied

Read showed the name; execute would have allowed the kernel to resolve test inside that directory.

Directory with execute but no read

Traverse-only directories hide names from ls but still allow access when you know the full path.

bash
chmod 711 /tmp/perm-lab/dir-x
bash
su - student -c 'ls /tmp/perm-lab/dir-x'

Sample output:

output
ls: cannot open directory '/tmp/perm-lab/dir-x': Permission denied
bash
su - student -c 'cat /tmp/perm-lab/dir-x/hidden.txt'

Sample output:

output
hidden content

No read bit means ls cannot enumerate entries, but execute still lets a known path work. Parent directories must also grant execute on every component of the path.


Change Permissions with chmod

chmod changes mode bits. Use symbolic form when you are toggling flags, and octal form when you are setting a complete triplet.

Symbolic mode

Symbolic syntax is who + operator + permissions:

  • Who: u owner, g group, o other, a all
  • Operator: + add, - remove, = set exactly
  • Permissions: r, w, x or combinations

Remove group write and other read on the script that still has mode 755 from the lab setup.

bash
chmod u+x,g-w,o-r /tmp/perm-lab/runme.sh
bash
ls -l /tmp/perm-lab/runme.sh

Sample output:

output
-rwxr-x--x. 1 root root 11 Aug  7 23:26 /tmp/perm-lab/runme.sh

Other users kept execute but lost read. Group is still root until the chgrp section below.

Numeric mode

Each digit is the sum of r=4, w=2, and x=1 for that class.

755 means owner 7 (4+2+1), group 5 (4+1), other 5 (4+1)—full control for the owner, read and execute for everyone else.

bash
chmod 755 /tmp/perm-lab/dir-rx
bash
ls -ld /tmp/perm-lab/dir-rx

Sample output:

output
drwxr-xr-x. 2 root root 6 Aug  7 23:16 /tmp/perm-lab/dir-rx

Build octal from what each class needs instead of copying 777 from a search result.


Change File Owner with chown

Ownership decides which user and group classes apply. Mode bits alone cannot grant access to the wrong owner.

Try reading a private file owned by root as student. The file must be root-owned with a restrictive mode for this denial to appear.

bash
chown root:root /tmp/perm-lab/private/secret.conf
bash
chmod 600 /tmp/perm-lab/private/secret.conf
bash
su - student -c 'cat /tmp/perm-lab/private/secret.conf'

Sample output:

output
cat: /tmp/perm-lab/private/secret.conf: Permission denied

The mode is 600, so only the owner may read. Transfer ownership when the file should belong to the application user. See the chown command for flags and edge cases; here is the everyday pattern.

bash
chown student:student /tmp/perm-lab/private/secret.conf
bash
ls -l /tmp/perm-lab/private/secret.conf

Sample output:

output
-rw-------. 1 student student 7 Aug  7 23:16 /tmp/perm-lab/private/secret.conf
bash
su - student -c 'cat /tmp/perm-lab/private/secret.conf'

Sample output:

output
secret

Use -R when an entire tree should change owner after a restore or deployment. By default, chown linkname changes the ownership of the file the symlink points to. Use chown -h when you specifically want to change ownership of the symbolic link itself. With -R, -H, -L, and -P control symlink traversal.


Change Group Ownership with chgrp

chgrp changes only the group field. Group members use the group triplet from ls -l.

bash
chgrp student /tmp/perm-lab/runme.sh
bash
ls -l /tmp/perm-lab/runme.sh

Sample output:

output
-rwxr-x--x. 1 root student 11 Aug  7 23:16 /tmp/perm-lab/runme.sh

The owner is still root, but members of group student now use the middle r-x triplet. Verify the user is in that group with id; see the chgrp command for recursive trees and numeric GID forms.


Change Permissions Recursively

chmod -R 755 directory applies the same mode to every file and subdirectory. That is often wrong: directories usually need execute for traverse, while plain data files rarely need execute.

bash
chmod -R 755 /tmp/perm-lab/web

If every file became 755, scripts and binaries might be fine, but configuration and HTML files carry unnecessary execute bits and look like a misconfiguration audit finding.

Safer pattern: directories 755, regular files 644. Add sample files if your web directory is empty.

bash
echo 'content' > /tmp/perm-lab/web/index.html
bash
echo 'config' > /tmp/perm-lab/web/app.conf
bash
find /tmp/perm-lab/web -type d -exec chmod 755 {} \;
bash
find /tmp/perm-lab/web -type f -exec chmod 644 {} \;
bash
find /tmp/perm-lab/web -printf '%m %p\n'

Sample output:

output
755 /tmp/perm-lab/web
644 /tmp/perm-lab/web/index.html
644 /tmp/perm-lab/web/app.conf

See chmod recursive for more find and chmod combinations on large trees.


Understand Permissions on Newly Created Files

New files inherit bits masked by umask, and that includes files produced by a copy, which is why cp can quietly hand you a stricter mode than the original. Our guide on how to create, copy, move and delete files shows when to add -p or -a to carry the source mode across. Check the current mask:

bash
umask

Sample output:

output
0022

With umask 0022, programs commonly request mode 0666 for regular files and 0777 for directories. The kernel then clears permission bits selected by the process's umask, which commonly produces 0644 files and 0755 directories. Full examples and login-session behavior are in the dedicated umask on Linux guide—this lesson only introduces why two users with the same role can still create different default modes.


Special Permissions: SUID, SGID and Sticky Bit

Three special bits extend the basic model. They show as s or t in ls -l when active.

Bit Octal prefix Typical use
SUID 4 Executable runs with owner's UID
SGID 2 Executable runs with group's GID, or new files inherit directory GID
Sticky 1 Restricts deletion/rename in shared directories to the file owner, directory owner, or a privileged process

SUID on an executablepasswd must update /etc/shadow as root:

bash
ls -l /usr/bin/passwd

Sample output:

output
-rwsr-xr-x. 1 root root 91424 Feb 23 05:30 /usr/bin/passwd

The s in the owner execute slot means SUID.

SGID on an executablewrite runs with group tty:

bash
ls -l /usr/bin/write

Sample output:

output
-rwxr-sr-x. 1 root tty 24160 Jan 15  2026 /usr/bin/write

SGID on a shared directory — new files inherit the directory group when the setgid bit is on the directory (useful for project folders).

Sticky bit on a directory — world-writable paths such as /tmp use sticky so ordinary users cannot delete or rename other users' files:

bash
ls -ld /tmp /tmp/perm-lab/shared

Sample output:

output
drwxrwxrwt. 29 root root 4096 Aug  7 23:18 /tmp
drwxrwxrwt.  2 root root    6 Aug  7 23:16 /tmp/perm-lab/shared

The t in other execute marks the sticky bit. This section names the bits only—hardening and auditing belong in dedicated security guides.


Diagnose Permission Denied Errors

Work through checks in order instead of widening modes blindly.

Start with the active user and group list for this shell.

bash
id student

Sample output:

output
uid=1001(student) gid=1001(student) groups=1001(student)

Then continue:

  1. File models -l path and stat -c '%a %U %G %n' path.
  2. Parent directories — every directory in the path needs execute for your user; a readable file in a 700 directory is still unreachable.
  3. Ownership — wrong owner after cp as root is a common surprise.
  4. ACLs+ after the mode in ls -l, or extra entries from getfacl, override basic triplets (. alone on RHEL usually marks SELinux context, not an ACL).
  5. SELinux — when DAC looks correct but access still fails, check ls -Z and audit logs.

Demonstrate parent directory blocking:

bash
chmod 700 /tmp/perm-lab/private
bash
su - student -c 'cat /tmp/perm-lab/private/secret.conf'

Sample output:

output
cat: /tmp/perm-lab/private/secret.conf: Permission denied

The file mode is still 600 for student, but the directory no longer grants traverse to others.

bash
chmod 755 /tmp/perm-lab/private

Restore traverse when you finish the test.


Understand Why Root Can Behave Differently

The superuser bypasses normal owner/group/other checks, which is why root can read a 600 file owned by another user. That does not mean every operation succeeds: SELinux may still deny a syscall, a read-only mount can block writes, and immutable or append-only attributes can block deletion or modification even for uid 0. nosuid has a different purpose—it disables setuid and setgid privilege elevation on that mount, not ordinary writes. When root sees Permission denied, look beyond chmod at MAC, mount options, and file attributes.


Common Permission Mistakes

Symptom Likely cause Fix
Quick fix applied everywhere chmod 777 habit Restore least privilege; see chmod 777 for why world-writable modes are risky
Scripts work, data files flagged chmod -R 755 on a mixed tree Use find to set 755 on dirs and 644 on files
File mode looks right, still denied Missing execute on a parent directory namei -l path or walk ls -ld on each parent
App cannot write after deploy Files owned by root from sudo cp chown to the service user
Group added but no effect Stale shell group list New login session or newgrp
DAC correct, access still fails ACL or SELinux getfacl, ls -Z, journal entries

Practical Permission Examples

These lab paths mirror common production choices.

Private configuration (600 on file, traverse on parent) — only the owner reads secrets.

bash
chmod 600 /tmp/perm-lab/private/secret.conf
bash
ls -l /tmp/perm-lab/private/secret.conf

Sample output:

output
-rw-------. 1 student student 7 Aug  7 23:16 /tmp/perm-lab/private/secret.conf

Executable script (755) — owner can edit; others may run.

bash
chmod 755 /tmp/perm-lab/runme.sh

Shared upload directory (1777 sticky) — anyone can create files; the sticky bit prevents ordinary users from deleting or renaming other users' entries.

bash
ls -ld /tmp/perm-lab/shared

Sample output:

output
drwxrwxrwt. 2 root root 6 Aug  7 23:16 /tmp/perm-lab/shared

Web content tree (755 directories, 644 files) — visitors read static assets; execute on directories only for traversal.

bash
find /tmp/perm-lab/web -printf '%m %p\n'

Sample output:

output
755 /tmp/perm-lab/web
644 /tmp/perm-lab/web/index.html
644 /tmp/perm-lab/web/app.conf

Match each mode to who must read, write, or traverse—not to the largest number you remember.


References


Summary

You mapped every path to an owner, a group, and three permission classes, then learned that r, w, and x mean different things on files versus directories. Listing a directory requires read; reaching a file inside requires execute on the directory and on each parent in the path. That distinction explains many “I can see the file in ls but cat fails” reports.

chmod sets those bits symbolically or in octal; chown and chgrp decide which user and group triplets apply. Recursive chmod -R 755 is a common mistake—use find to give directories execute without marking every document executable. New objects inherit umask, and SUID, SGID, and sticky bits cover the exceptions you still see in /usr/bin/passwd and /tmp.

When Permission denied appears, walk identity, mode, parents, ownership, ACLs, and SELinux before reaching for world-writable modes. The RHCSA tutorial syllabus continues with deeper ownership and security topics; ACL and SELinux administration stay in their own guides rather than on this page.


Frequently Asked Questions

1. What is the difference between chmod 755 and chmod 644?

644 is typical for regular files: owner read/write, everyone else read only, no execute bit. 755 adds execute for all three classes and is common on directories and executable programs. Applying 755 to every file in a tree is usually wrong because most data files do not need execute.

2. Why can I list a directory but not open files inside it?

On directories, read lets you see entry names while execute lets you traverse into the directory and access inode metadata for those names. A directory with read but no execute can still show names in ls, yet cat or cd into paths inside may fail.

3. Does chmod 777 fix permission denied errors?

It often masks the real problem and exposes files to every user on the system. Fix ownership, parent directory traverse bits, group membership, ACLs, or SELinux context instead. World-writable modes are a last resort in isolated lab sandboxes, not production servers.

4. Why does chown or chmod still fail after I log in as a new group?

Group membership is evaluated when your session starts. After usermod adds a group, open a new login shell or use newgrp so id shows the group before you expect group permissions to apply.

5. Can root always read and write every file?

Root bypasses ordinary DAC permission checks, but SELinux, a read-only mount, immutable or append-only file attributes, and other kernel restrictions can still block operations. nosuid disables setuid and setgid privilege elevation on a mount; it does not make files unwritable. Permission denied for root often points to SELinux or mount attributes rather than missing chmod bits.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)