Operations 33 min read

Master Linux File Permissions: How to Use chmod and chown Effectively

This comprehensive guide explains Linux's permission model, demonstrates numeric and symbolic chmod usage, details chown operations, introduces ACL for fine‑grained control, and provides troubleshooting steps and security best practices for production environments.

Raymond Ops
Raymond Ops
Raymond Ops
Master Linux File Permissions: How to Use chmod and chown Effectively

Background and Scenarios

Linux is a multi‑user operating system where file‑permission management is the foundation of system security. Correct permissions prevent unauthorized access, limit user actions, and protect sensitive data on everything from personal VPS instances to large enterprise servers.

Part 1: Core Permission Model

Basic Permission Model

Each file has three sets of permissions: Owner (u) , Group (g) , and Others (o) . Each set contains three bits: read (r = 4), write (w = 2), and execute (x = 1). Example output of ls -l /var/log/syslog shows the breakdown of these bits and the file type indicator.

ls -l /var/log/syslog
-rw-r----- 1 syslog adm 12345 May 29 10:30 /var/log/syslog

Permission and Directory Relationship

For files, r allows reading content, w allows modifying, and x allows execution. For directories, r lists filenames, w creates/deletes/renames entries, and x permits entering the directory. The write bit on a directory controls deletion regardless of the file’s own permissions.

Default Permissions and umask

When a new file or directory is created, the system applies default permissions reduced by the umask value. Typical umask values are 0022 (resulting in 644 files and 755 directories) or 0002. Commands:

umask          # show current umask (e.g., 0022)
umask 0027     # set temporary umask for the current shell

Permanent changes are made in shell startup files such as ~/.bashrc or /etc/profile.

Part 2: chmod Details

Numeric Mode

Most common usage uses three octal digits: chmod 755 file # rwxr-xr-x, chmod 644 file # rw-r--r--, chmod 600 file # rw-------, chmod 700 dir # rwx------. The digits map to Owner‑Group‑Others permissions.

# chmod ABC path
# A = Owner permissions
# B = Group permissions
# C = Others permissions
# 755 means: Owner rwx, Group r-x, Others r-x

Symbolic Mode

More granular control uses who ( u,g,o,a), operator ( +, -, =), and permission ( r,w,x). Common examples:

chmod u+x script.sh               # add execute for owner
chmod g-w file.txt                # remove write for group
chmod o=r file.txt                # set others to read‑only
chmod a+rx program                # add read & execute for all
chmod u=rwx,go=rx file            # owner rwx, group & others r-x

Combined Operations

Modify multiple classes at once:

chmod ug+rw file.txt               # owner & group get read/write
chmod u=rwx,g=rx,o=r file         # explicit set for each class

Recursive Changes

Apply permissions to a directory tree:

chmod -R 755 /var/www/html                 # all files & dirs
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;

Common Permission Values

777 rwxrwxrwx – dangerous, gives everyone full access

755 rwxr-xr-x – executable files or public directories

750 rwxr-x--- – private directories (owner & group only)

700 rwx------ – private files, owner only

644 rw-r--r-- – public files, configuration files

600 rw------- – private files, e.g., SSH keys

Part 3: chown Details

Basic Usage

Change file owner:

chown user /path/to/file               # only owner
chown user:group /path/to/file          # owner and group
chown :group /path/to/file              # only group

Recursive Change

chown -R user:group /path/to/directory

Reference File

chown --reference=/etc/passwd /etc/shadow   # copy owner/group from another file

Common Scenarios

Web applications : chown -R www-data:www-data /var/www/html or separate users for Nginx and PHP‑FPM.

Databases : chown -R mysql:mysql /var/lib/mysql and chmod -R 700 /var/lib/mysql (similarly for PostgreSQL).

Log directories : chown -R myapp:adm /var/log/myapp and chmod -R 750 /var/log/myapp.

Service configuration : chown -R root:root /etc/nginx and chmod 640 /etc/nginx/*.conf.

Part 4: ACL (Access Control List)

Check ACL Support

Most modern filesystems (ext4, xfs, btrfs) support ACL. Enable temporarily with:

tune2fs -o acl /dev/sda1
mount -o acl /dev/sda1 /mnt

View ACL

getfacl /path/to/file

Sample output shows entries for specific users, groups, mask, and others.

Set ACL

# User specific
setfacl -m u:alice:rw /var/www/html/file.txt
# Group specific
setfacl -m g:developers:rx /var/www/html/dir
# Default ACL for new files in a directory
setfacl -m d:u:www-data:rw /var/www/html/uploads

ACL vs Traditional Permissions

Traditional permissions are the baseline; ACL adds finer‑grained entries. Effective permissions are limited by the mask entry ( mask::).

Web App ACL Example

# Nginx reads, PHP‑FPM writes
chown nginx:nginx /var/www/html
chmod 750 /var/www/html
setfacl -R -m u:php-fpm:rw /var/www/html/uploads
setfacl -R -m u:nginx:rx /var/www/html/uploads
setfacl -R -m d:u:php-fpm:rw /var/www/html/uploads

Backup and Restore

# Backup ACLs
getfacl -R /etc/nginx > /backup/nginx_acl_$(date +%Y%m%d).txt
# Restore
setfacl --restore=/backup/nginx_acl_20260529.txt

Part 5: Production Troubleshooting

Problem 1 – Web app cannot read files (403 Forbidden)

Steps:

Check Nginx error log ( tail -20 /var/log/nginx/error.log).

Inspect file permissions ( ls -la /var/www/html/index.html).

Verify Nginx run‑user ( ps aux | grep nginx).

Common causes: wrong owner, missing directory execute bit, SELinux/AppArmor restrictions.

Solution:

# Ensure correct owner
chown nginx:nginx /var/www/html/index.html
# Directory execute permission
chmod 755 /var/www/html
# File read permission
chmod 644 /var/www/html/index.html

Problem 2 – Web app cannot write files (uploads, logs)

Steps: check PHP‑FPM logs, directory permissions, PHP‑FPM user, filesystem writability.

# Fix ownership and write permission
chown php-fpm:php-fpm /var/www/html/uploads
chmod 775 /var/www/html/uploads
# If SELinux is enforcing
chcon -R -t httpd_sys_rw_content_t /var/www/html/uploads
semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/html/uploads(/.*)?"
restorecon -R /var/www/html/uploads

Problem 3 – Database cannot start (MySQL/PostgreSQL)

Check error logs, data directory permissions, and config file permissions. Example fix for MySQL:

systemctl stop mysql
chown -R mysql:mysql /var/lib/mysql
chmod -R 700 /var/lib/mysql
systemctl start mysql

Problem 4 – SSH key login fails

Correct permissions:

chmod 700 /home/username/.ssh
chmod 600 /home/username/.ssh/authorized_keys
chmod 755 /home/username

Problem 5 – Script "Permission denied"

Add execute bit:

chmod +x script.sh   # or chmod 755 script.sh

Problem 6 – Shared directory access

Use SGID so new files inherit the directory’s group, and set a permissive umask for the team:

chmod 2775 /shared               # SGID + rwx for owner & group
chown :developers /shared
umask 002                         # ensures new files are 664

Part 6: Security Best Practices

Principle of Least Privilege

Never apply chmod -R 777 on production paths. Use find to set directories to 755 and files to 644, and grant write permission only where needed.

# Apply least‑privilege defaults
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;
chmod 775 /var/www/html/uploads
chown www-data:www-data /var/www/html/uploads

Sensitive File Protection

# Password files
chmod 640 /etc/passwd
chmod 600 /etc/shadow
# SSH private key
chmod 600 ~/.ssh/id_rsa
chmod 644 ~/.ssh/id_rsa.pub
# Database configs
chmod 640 /etc/mysql/my.cnf
chmod 640 /etc/postgresql/*/main/pg_hba.conf
# Application secrets
chmod 600 /var/www/html/.env

Service‑Specific Users

useradd -r -s /sbin/nologin nginx
useradd -r -s /sbin/nologin php-fpm
useradd -r -s /sbin/nologin mysql
useradd -r -s /sbin/nologin postgres
useradd -m -s /bin/bash myapp

Regular Audits

#!/bin/bash
echo "=== Permission Audit Report ==="
echo "Time: $(date)"
# Sensitive files
for file in /etc/passwd /etc/shadow /etc/group; do
  perms=$(stat -c "%a" $file)
  owner=$(stat -c "%U:%G" $file)
  echo "$file: $owner $perms"
done
# Find dangerous 777 files/dirs
echo "--- 777 files/dirs (dangerous) ---"
find /var/www -perm -007 -type f 2>/dev/null | head -10
find /var/www -perm -007 -type d 2>/dev/null | head -10
# Executable files in /tmp
echo "--- Suspicious executables in /tmp ---"
find /tmp -perm /111 -type f 2>/dev/null | head -10

Directory Permission Standards

/home/user – 755 (home directory)

/home/user/.ssh – 700 (SSH keys)

/var/www/html – 755 (web root)

/var/www/html/uploads – 775 (upload dir)

/var/log/app – 750 (application logs)

/data/shared – 2775 (shared dir with SGID)

/tmp – 1777 (sticky‑bit temporary dir)

/etc/nginx – 750 (config files)

/var/lib/mysql – 700 (MySQL data)

umask Recommendations

System‑wide ( /etc/profile) set to 0027. For team shared directories add in user profiles:

# In ~/.bashrc for developers group
if [ "$(id -gn)" = "developers" ]; then
  umask 002
fi
# Web‑app user
su - www-data -c "umask 002"

Part 7: Risks and Rollback

High‑Risk Operations

chmod -R 777 – high risk, grants full access.

chmod -R 000 – high risk, locks out all access.

chown -R root:root / – extremely high risk, can break the system.

chmod -x /bin/* – extremely high risk, may render the system unbootable.

Modifying /etc/shadow permissions – high risk, must backup first.

Backup Before Change

# Backup ACLs
getfacl -R /etc/nginx > /backup/nginx_acl_$(date +%Y%m%d).txt
getfacl /etc/passwd > /backup/passwd_acl.txt

Restore

setfacl --restore=/backup/nginx_acl_20260529.txt
setfacl --restore=/backup/passwd_acl.txt

Rollback Procedure

Locate original permissions from version control, backup, or documentation.

Use setfacl --restore=backup.txt if an ACL backup exists.

For standard files, revert to typical defaults (e.g., chmod 644 file, chmod 755 dir, chmod 640 /etc/passwd, chmod 600 /etc/shadow).

Part 8: Special Bits Deep Dive

SUID Practical Use

SUID allows a program to run with the file owner’s privileges. Common example: /bin/ping is owned by root with the SUID bit set, enabling ordinary users to send ICMP packets.

ls -l /bin/ping
-rwsr-xr-x 1 root root 4096 May 29 10:30 /bin/ping   # s indicates SUID

Find all SUID binaries:

find /usr -perm /4000 -type f 2>/dev/null
find / -perm -4000 -type f 2>/dev/null | grep -vE "^/(usr|bin|sbin)/"

Remove SUID when not needed:

chmod u-s /usr/bin/someprogram   # or chmod 755 /usr/bin/someprogram

SGID Practical Use

On directories, SGID forces new files to inherit the directory’s group. Example shared directory for a development team:

mkdir /opt/shared
groupadd developers
chown :developers /opt/shared
chmod 2775 /opt/shared   # SGID (2) + rwx for owner/group, r-x for others
usermod -aG developers alice
usermod -aG developers bob
# Verify
su - alice -c "touch /opt/shared/alice_file.txt"
ls -l /opt/shared/alice_file.txt   # shows group 'developers' and rw-rw-r--

Multiple groups can be granted via ACL:

mkdir /data/project
chown :dev /data/project
chmod 2770 /data/project
setfacl -m g:qa:rw /data/project
setfacl -m d:g:qa:rw /data/project
getfacl /data/project

Sticky Bit Practical Use

Sticky Bit on public directories (e.g., /tmp) ensures users can only delete their own files.

ls -ld /tmp
 drwxrwxrwt 10 root root 4096 May 29 10:30 /tmp   # t indicates Sticky Bit
chmod 1777 /opt/public
chown root:root /opt/public   # anyone can write, but only owners can delete

SELinux/AppArmor Interaction

Check SELinux status:

getenforce          # Enforcing, Permissive, or Disabled
sestatus
ls -Z /var/www/html   # show SELinux context
chcon -R -t httpd_sys_content_t /var/www/html
semanage fcontext -a -t httpd_sys_content_t "/var/www/html(/.*)?"
restorecon -R /var/www/html

AppArmor (Ubuntu) commands:

aa-status
cat /etc/apparmor.d/usr.sbin.nginx
systemctl reload apparmor

Conclusion

Understanding Linux's permission model, mastering chmod and chown, and leveraging ACL, SUID/SGID, and the Sticky Bit are essential skills for reliable and secure system administration. Regular audits, proper backups, and adherence to the principle of least privilege prevent most production incidents.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

operationsLinuxsecurityaclchmodchownfile-permissionsumask
Raymond Ops
Written by

Raymond Ops

Linux ops automation, cloud-native, Kubernetes, SRE, DevOps, Python, Golang and related tech discussions.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.