Table of Contents Link to heading
- File Ownership Model
- Changing Ownership
- Permission Model
- Changing Permissions: chmod
- Inspecting Permissions: stat
- Default Permissions: umask
File Ownership Model Link to heading
Every file and directory on a Linux system has two owners: a user owner and a group owner. Ownership determines which permission set applies when a user accesses the file.
- The user owner is typically the account that created the file. Only the root user can change the user owner of a file.
- The group owner defaults to the primary group of the user who created the file. The file owner (or root) can change the group to any group they belong to.
Internally, the operating system tracks ownership by UID (user ID) and GID (group ID), not by name. When you see a username in ls -l output, the system looked up the name from /etc/passwd using the stored UID.
ls -l /etc/nginx/nginx.conf
# -rw-r--r-- 1 root root 2657 Jan 10 09:23 /etc/nginx/nginx.conf
# ^ ^
# user group owner
Undefined Ownership Link to heading
If a user account is deleted or its UID is changed, files previously owned by that UID will display the numeric UID instead of a username — because no entry in /etc/passwd maps to that UID anymore. The same applies to group ownership and GIDs. This is called an orphaned file.
ls -l /home/deleted_user/
# -rw-r--r-- 1 1042 1042 1234 Jan 01 00:00 file.txt
# ^ ^
# raw UID/GID (no matching account in /etc/passwd)
To find files owned by a specific UID (useful after account deletion):
find / -uid 1042 2>/dev/null
find / -nouser 2>/dev/null # files with no matching owner in /etc/passwd
find / -nogroup 2>/dev/null # files with no matching group in /etc/group
Changing Ownership Link to heading
For verifying your current identity and group memberships, see id command.
newgrp: Temporarily Change Primary Group Link to heading
newgrp opens a new shell session with a different primary group — new files created in that session will be owned by the specified group instead of the user’s default primary group:
newgrp developers # switch primary group to 'developers' for this session
# now create files — they will be owned by group 'developers'
exit # return to original shell and primary group
To permanently change a user’s primary group, root must modify the /etc/passwd entry:
sudo usermod --gid developers username
chgrp: Change Group Owner Link to heading
chgrp changes the group owner of files and directories. The root user can change any file’s group; regular users can only change group ownership to a group they belong to.
# Change group of a file
chgrp developers /srv/project/app.conf
# Change group recursively
chgrp -R developers /srv/project/
# Change group of a symlink (not its target)
chgrp -h developers /srv/project/current
# Match group of a reference file
chgrp --reference=/srv/reference.conf /srv/project/app.conf
chown: Change User and Group Owner Link to heading
chown changes the user owner, group owner, or both. Only root can change the user owner of a file. Regular users can use chown to change the group, but only to groups they belong to.
# Change user owner only
chown www-data /var/www/html/index.html
# Change group owner only (colon prefix, no user)
chown :webteam /var/www/html/
chown .webteam /var/www/html/ # dot syntax (equivalent)
# Change both user and group
chown www-data:webteam /var/www/html/
chown www-data.webteam /var/www/html/ # dot syntax
# Recursive (all files and subdirectories)
chown -R www-data:webteam /var/www/html/
# Change ownership of a symlink (not the target)
chown -h www-data:webteam /var/www/current
# Match ownership of a reference file
chown --reference=/var/www/html/index.html /var/www/html/style.css
chown -R on a large directory tree (especially / or /usr) is one of the most destructive commands you can run. A single mistyped path can change ownership of system binaries, making the system unbootable. Always double-check the path with ls before running chown -R as root.Permission Model Link to heading
Read more at Long Display Listing
Linux file permissions use a 9-bit model — three sets of three bits, one set for each of: owner, group, others (world).
-rw-r--r-- 1 kali kali 45665 Nov 24 22:11 vimrc
↑↑↑↑↑↑↑↑↑
│└──┘└──┘└──┘
│ Owner Group Others
File type
Permission Sets: Owner, Group, Others Link to heading
| Set | Who it applies to |
|---|---|
| Owner (user) | The user account that owns the file |
| Group | Any user who is a member of the file’s group owner |
| Others | Everyone else (not the owner, not in the group) |
Permissions are evaluated in order: owner → group → others. The first matching set applies — if you are the file owner, the owner permissions apply and the group/others sets are ignored entirely, even if those sets are more permissive.
Read Permission Link to heading
| Context | Effect |
|---|---|
| Regular file | Process can open and read the file’s contents |
| Directory | Process can list the directory’s contents (ls) |
Without read on a directory, ls will fail — but you may still be able to access files inside if you know their names and have execute permission on the directory.
Write Permission Link to heading
| Context | Effect |
|---|---|
| Regular file | Process can modify the file’s contents |
| Directory | Process can create, rename, or delete files within the directory |
/tmp uses the sticky bit to prevent this.Execute Permission Link to heading
| Context | Effect |
|---|---|
| Regular file | Process can execute the file as a program |
| Directory | Process can enter the directory (cd) and use it as part of a path |
Directory execute permission is often called the search bit — it allows the directory to be traversed as part of a path resolution. Without it, even cat /path/to/dir/file fails if dir lacks execute, regardless of permissions on file itself.
Changing Permissions: chmod Link to heading
chmod modifies the permission bits of files and directories. Two syntaxes are supported — symbolic for clarity, numeric for scripting.
Symbolic Method Link to heading
Symbolic chmod uses three components: who + action + permission:
| Who | Meaning |
|---|---|
u |
User owner |
g |
Group owner |
o |
Others |
a |
All (equivalent to ugo) |
| Action | Meaning |
|---|---|
+ |
Add permission |
- |
Remove permission |
= |
Set exactly (replace current bits) |
| Permission | Meaning |
|---|---|
r |
Read |
w |
Write |
x |
Execute |
X |
Execute only if directory or already executable by someone |
# Add execute for the owner
chmod u+x script.sh
# Add read and write for owner
chmod u+rw file.txt
# Remove execute from group
chmod g-x binary
# Give everyone read and execute
chmod a+rx /usr/local/bin/tool
# Set others to match group permissions
chmod o=g file.txt
# Remove all permissions from others
chmod o= file.txt
# Recursive: add write for group and others
chmod -R g+w,o+w /srv/shared/
# Recursive: add read for all, execute for directories only
chmod -R a+rX /srv/data/
Numeric (Octal) Method Link to heading
Each permission bit has a numeric value. Sum the values for each set:
| Bit | Value | Meaning |
|---|---|---|
| r | 4 | Read |
| w | 2 | Write |
| x | 1 | Execute |
| — | 0 | No permission |
A three-digit octal number specifies permissions for owner, group, and others in order:
| Numeric | Symbolic | Meaning |
|---|---|---|
| 7 | rwx |
Full access |
| 6 | rw- |
Read and write |
| 5 | r-x |
Read and execute |
| 4 | r-- |
Read only |
| 3 | -wx |
Write and execute |
| 2 | -w- |
Write only |
| 1 | --x |
Execute only |
| 0 | --- |
No permissions |
chmod 755 script.sh # rwxr-xr-x (owner: full, group: r+x, others: r+x)
chmod 644 config.txt # rw-r--r-- (owner: r+w, group: r, others: r)
chmod 600 private.key # rw------- (owner: r+w, group: none, others: none)
chmod 750 /srv/app/ # rwxr-x--- (owner: full, group: r+x, others: none)
chmod 700 ~/.ssh/ # rwx------ (owner: full, group: none, others: none)
Common permission patterns for sysadmins:
| Pattern | Octal | Use case |
|---|---|---|
rwxr-xr-x |
755 | Standard executable, public directory |
rw-r--r-- |
644 | Standard configuration file |
rw------- |
600 | Private key, sensitive config |
rwxrwxr-x |
775 | Shared project directory |
rwxrwxrwt |
1777 | World-writable with sticky bit (like /tmp) |
rwsr-xr-x |
4755 | setuid executable |
rwxr-sr-x |
2755 | setgid directory |
Inspecting Permissions: stat Link to heading
stat provides more detailed file metadata than ls -l, including the octal permission representation:
stat /etc/passwd
# File: /etc/passwd
# Size: 2847 Blocks: 8 IO Block: 4096
# Device: fd00h/64768d Inode: 1442 Links: 1
# Access: (0644/-rw-r--r--) Uid: (0/root) Gid: (0/root)
# Access: 2024-01-15 09:23:41
# Modify: 2024-01-10 14:32:18
# Change: 2024-01-10 14:32:18
# Show only the octal permissions and filename
stat --format="%a %n" /etc/passwd # outputs: 644 /etc/passwd
# Show owner and group
stat --format="%U %G %n" /etc/passwd # outputs: root root /etc/passwd
# Show file size in bytes
stat --format="%s %n" /etc/passwd
# Check a filesystem's stats
stat --file-system /var/log/
Default Permissions: umask Link to heading
When a new file or directory is created, the kernel starts with a maximum permission set and subtracts the umask — a bitmask of permissions to withhold:
- Files default maximum:
666(rw-rw-rw-) — execute is never granted by default - Directories default maximum:
777(rwxrwxrwx)
File default: 666 (rw-rw-rw-)
Minus umask: -022 (----w--w-)
Result: 644 (rw-r--r--)
Directory default: 777 (rwxrwxrwx)
Minus umask: -022 (----w--w-)
Result: 755 (rwxr-xr-x)
umask # display current umask (octal)
umask -S # display in symbolic form (e.g., u=rwx,g=rx,o=rx)
# Change umask for the current session
umask 027 # new files: 640, new directories: 750
umask 077 # new files: 600, new directories: 700 (private)
umask 002 # new files: 664, new directories: 775 (group-writable)
Common umask values:
| umask | New files | New directories | Use case |
|---|---|---|---|
022 |
644 |
755 |
Standard (most distributions default) |
027 |
640 |
750 |
More restrictive — deny others entirely |
077 |
600 |
700 |
Maximum privacy — deny group and others |
002 |
664 |
775 |
Collaborative — allow group to write |
The umask set in a shell session applies only to that session. For persistent umask changes:
- Per-user: add
umask 027to~/.bashrcor~/.bash_profile - System-wide: add to
/etc/profileor/etc/profile.d/umask.sh - PAM-based: configure in
/etc/pam.d/via thepam_umaskmodule