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

This comprehensive guide explains Linux's permission model, the core concepts of owner, group, and others, demonstrates numeric and symbolic chmod usage, details chown operations, explores special bits, ACLs, common real‑world scenarios, troubleshooting steps, security best practices, and provides scripts for auditing and rollback.

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

Linux Permission Model

Every file and directory has three sets of permissions: owner (user), group, and others. Each set consists of three bits: read (r = 4), write (w = 2), and execute (x = 1). The combination of the three bits is expressed as an octal value.

Viewing permissions

Use ls -l to display the full mode string. ls -l /var/log/syslog Example output:

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

Interpretation:

Owner: read + write

Group: read only

Others: no access

File type: regular file

Numeric representation

The octal value is the sum of the bits for each class (owner‑group‑others). Common values:

0 = --- (no permissions)

1 = --x (execute only)

2 = -w- (write only)

3 = -wx (write + execute)

4 = r-- (read only)

5 = r-x (read + execute)

6 = rw- (read + write)

7 = rwx (all three)

Directory semantics

r – list filenames

w – create, delete, rename entries

x – enter the directory (cd)

Note: write permission on a directory allows deletion of files inside it regardless of the file’s own mode.

Default permissions and umask

New files are created with mode 666 and new directories with 777. The process umask value is subtracted from these defaults. umask Typical values are 0022 (resulting in 0644 files, 0755 directories) or 0002 (0644 files, 0775 directories).

Temporary change (current shell only): umask 0027 Permanent change: add the umask command to ~/.bashrc or /etc/profile.

chmod – Changing mode

Numeric (octal) form

# rwxr-xr-x
chmod 755 /path/to/file
# rw-r--r--
chmod 644 /path/to/file
# rw-------
chmod 600 /path/to/file
# rwx------ (directory)
chmod 700 /path/to/directory

Explanation: the first digit is for the owner, the second for the group, the third for others.

Symbolic form

# Syntax: chmod [who][op][perm] file
# who: u (owner), g (group), o (others), a (all)
# op: + (add), - (remove), = (set exactly)
# perm: r, w, x

Common examples:

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

Combined operations

# owner & group get rw
chmod ug+rw file.txt
# owner rwx, group rx, others r
chmod u=rwx,g=rx,o=r file

Recursive changes

# whole tree
chmod -R 755 /var/www/html
# only files
find /var/www/html -type f -exec chmod 644 {} \;
# only directories
find /var/www/html -type d -exec chmod 755 {} \;

Common numeric values

777 – rwxrwxrwx (dangerous, world‑writable)

755 – rwxr-xr-x (executables, public directories)

750 – rwxr-x--- (private directory, owner & group)

700 – rwx------ (private file)

644 – rw-r--r-- (public files, configs)

600 – rw------- (private files, e.g., secrets)

500 – r-x------ (owner read & execute)

400 – r-------- (read‑only, e.g., password files)

Special permission bits

SUID (4xxx) – program runs with file owner’s UID. Set with chmod u+s file or chmod 4755 file. Typical use: /usr/bin/passwd (needs access to /etc/shadow).

SGID (2xxx) – program runs with file group’s GID; on directories new files inherit the directory’s group. Set with chmod g+s dir or chmod 2755 dir. Typical use: shared project directories.

Sticky Bit (1xxx) – on directories, only the file’s owner may delete/rename it. Set with chmod +t /shared or chmod 1777 /shared. Typical use: /tmp.

chown – Changing owner

Basic usage

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

Recursive

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

Reference file

chown --reference=/etc/passwd /etc/shadow

This copies the owner and group from /etc/passwd to /etc/shadow.

Common scenarios

Web applications (Nginx + PHP‑FPM)

# same user for both services
chown -R www-data:www-data /var/www/html
# separate users (recommended for production)
chown -R nginx:nginx /var/www/html          # web server files
chown -R php-fpm:php-fpm /var/www/html/uploads  # upload dir
# ACL alternative
setfacl -R -m u:nginx:rx /var/www/html/uploads
setfacl -R -m u:php-fpm:rw /var/www/html/uploads

Database files

# MySQL
chown -R mysql:mysql /var/lib/mysql
chmod -R 700 /var/lib/mysql
# PostgreSQL
chown -R postgres:postgres /var/lib/postgresql
chmod -R 700 /var/lib/postgresql

Log directories

chown -R myapp:adm /var/log/myapp
chmod -R 750 /var/log/myapp

Service configuration

chown -R root:root /etc/nginx
chmod -R 640 /etc/nginx/*.conf
chmod 755 /etc/nginx

User and group management

# create a regular user (auto‑creates same‑named group)
useradd -m -s /bin/bash deploy
# create a system user without home and login shell
useradd -r -s /sbin/nologin nginx
# create a group
groupadd developers
# add user to group
usermod -aG developers alice
# view groups of a user
groups alice
id alice

ACL – Access Control Lists

Checking ACL support

# enable ACL on ext4 (if not already)
tune2fs -o acl /dev/sda1
mount -o acl /dev/sda1 /mnt

Viewing ACLs

getfacl /path/to/file

Sample output:

# file: file.txt
# owner: root
# group: root
user::rw-
user:www-data:rw-
group::r--
group:developers:rw-
mask::rw-
other::r--

Setting ACL entries

# grant user read/write
setfacl -m u:alice:rw /var/www/html/file.txt
# grant group read/execute on a directory
setfacl -m g:dev:rx /var/www/html/dir

Default ACLs (inheritance)

# default ACL for new files in uploads
setfacl -m d:u:www-data:rw /var/www/html/uploads
# verify
getfacl /var/www/html/uploads

Removing ACL entries

setfacl -x u:alice /path/to/file
setfacl -x g:dev /path/to/file
# remove all ACLs (revert to traditional mode)
setfacl -b /path/to/file

Recursive ACL operations

# apply to all files & sub‑dirs
setfacl -R -m u:www-data:rw /var/www/html/uploads
# set default ACL (affects only newly created items)
setfacl -R -m d:u:www-data:rw /var/www/html/uploads

Mask

The effective permission is limited by the mask entry.

setfacl -m m::rwx /path/to/file

Web‑application ACL example (nginx + php‑fpm)

# directory owned by nginx, readable by nginx, writable by php‑fpm
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
# default ACL so new uploads inherit the same rights
setfacl -R -m d:u:php-fpm:rw /var/www/html/uploads
setfacl -R -m d:u:nginx:rx /var/www/html/uploads

Production‑environment troubleshooting

1 – Web server cannot read files (403)

Steps:

Check Nginx error log: tail -20 /var/log/nginx/error.log Inspect file mode: ls -la /var/www/html/index.html Identify Nginx run‑user: ps aux | grep nginx Typical causes: wrong owner, missing execute on parent directories, SELinux/AppArmor denial.

# fix ownership and permissions
chown nginx:nginx /var/www/html/index.html
chmod 755 /var/www/html          # directory execute
chmod 644 /var/www/html/index.html

2 – Web server cannot write (uploads, logs)

Steps:

Check PHP‑FPM or application logs.

Inspect upload directory: ls -ld /var/www/html/uploads Confirm PHP‑FPM user: ps aux | grep php-fpm Verify filesystem is writable: df -h /var/www/html/uploads and

mount | grep /var/www
# make uploads writable for php‑fpm
chown php-fpm:php-fpm /var/www/html/uploads
chmod 775 /var/www/html/uploads
# SELinux context (if enabled)
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(/.*)?"

3 – Database service fails to start

Steps:

Inspect DB error log ( /var/log/mysql/error.log or /var/log/postgresql/postgresql-*-main.log).

Check data directory permissions.

Check configuration file permissions.

# MySQL repair
systemctl stop mysql
chown -R mysql:mysql /var/lib/mysql
chmod -R 700 /var/lib/mysql
systemctl start mysql
# PostgreSQL repair
systemctl stop postgresql
chown -R postgres:postgres /var/lib/postgresql
chmod -R 700 /var/lib/postgresql
systemctl start postgresql

4 – SSH public‑key login fails

Required permissions:

/home/username      700 or 755
/home/username/.ssh 700
/home/username/.ssh/authorized_keys 600
# fix permissions
chmod 700 /home/username/.ssh
chmod 600 /home/username/.ssh/authorized_keys
chmod 755 /home/username

5 – Script execution “Permission denied”

Check that the script is executable and has a proper shebang.

# add execute bit
chmod +x script.sh
# or set explicit mode
chmod 755 script.sh
# verify interpreter is executable
ls -la /bin/bash

6 – Shared directory users cannot access each other’s files

Solution: enable SGID on the directory and adjust umask so new files are group‑writable.

# set SGID and group ownership
chmod 2775 /shared
chown :developers /shared
# ensure new files get group write
umask 002   # add to ~/.bashrc or /etc/profile for the relevant users

Security best practices

Principle of least privilege

Grant only the permissions required for a task.

# avoid world‑writable directories
chmod -R 777 /var/www/html   # NOT recommended
# recommended layout for a web site
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

Dedicated service 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 permission audit

Example audit script:

#!/bin/bash

echo "=== Permission audit report ==="
echo "Time: $(date)"

echo "--- Sensitive files ---"
for f in /etc/passwd /etc/shadow /etc/group; do
  perms=$(stat -c "%a" $f)
  owner=$(stat -c "%U:%G" $f)
  echo "$f: $owner $perms"
done

echo "--- World‑writable (777) files/dirs ---"
find /var/www -perm -007 -type f 2>/dev/null | head -10
find /var/www -perm -007 -type d 2>/dev/null | head -10

echo "--- Suspicious executables in /tmp ---"
find /tmp -perm /111 -type f 2>/dev/null | head -10

Directory permission recommendations

/home/user – 755

/home/user/.ssh – 700

/var/www/html – 755

/var/www/html/uploads – 775

/var/log/app – 750

/data/shared – 2775 (SGID)

/tmp – 1777 (Sticky Bit)

/etc/nginx – 750

/var/lib/mysql – 700

Umask recommendations

# system‑wide default (e.g., /etc/profile)
umask 0027
# team‑shared directory (in ~/.bashrc for members of "developers")
if [ "$(id -gn)" = "developers" ]; then
  umask 002
fi
# web‑app user
su - www-data -c "umask 002"

Special permission deep‑dive

SUID

Allows a program to run with the file owner’s UID. Common example: /bin/ping is setuid root so ordinary users can send ICMP packets.

# list SUID binaries
find /usr -perm /4000 -type f 2>/dev/null
# detailed list
find /usr -perm /4000 -type f -exec ls -la {} \; 2>/dev/null
# exclude standard system binaries
find / -perm -4000 -type f 2>/dev/null | grep -vE "^/(usr|bin|sbin)/"

Security risk: any SUID binary can be abused for privilege escalation. Periodic checks are recommended.

#!/bin/bash
KNOWN="/root/.known_suid_$(date +%Y%m)"
if [ ! -f "$KNOWN" ]; then
  find / -perm -4000 -type f 2>/dev/null > "$KNOWN"
  echo "Created baseline SUID list: $KNOWN"
  exit 0
fi
CURRENT=$(mktemp)
find / -perm -4000 -type f 2>/dev/null > "$CURRENT"
NEW=$(comm -13 "$KNOWN" "$CURRENT")
if [ -n "$NEW" ]; then
  echo "New SUID files detected:"
  echo "$NEW"
else
  echo "No new SUID files"
fi
rm -f "$CURRENT"

To remove SUID from a binary:

chmod u-s /usr/bin/someprogram
# or reset to normal executable mode
chmod 755 /usr/bin/someprogram

SGID

Two uses: setgid on a file (run with file’s group) and setgid on a directory (new files inherit the directory’s group).

# create a shared directory for developers
mkdir /opt/shared
groupadd developers
chown :developers /opt/shared
chmod 2775 /opt/shared   # SGID bit set
# add members
usermod -aG developers alice
usermod -aG developers bob
# verify inheritance
su - alice -c "touch /opt/shared/alice.txt"
ls -l /opt/shared/alice.txt   # group should be developers

When multiple groups need write access, combine SGID with ACL:

mkdir /data/project
groupadd dev
groupadd qa
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

Used on public directories so users can only delete their own files.

# typical /tmp directory
ls -ld /tmp   # drwxrwxrwt … (t = sticky)
# create a custom public dir
mkdir /opt/public
chmod 1777 /opt/public
chown root:root /opt/public

SELinux / AppArmor interaction

SELinux

# status
getenforce
sestatus
# view context of a path
ls -Z /var/www/html
# change context temporarily
chcon -R -t httpd_sys_content_t /var/www/html
# change context permanently
semanage fcontext -a -t httpd_sys_content_t "/var/www/html(/.*)?"
restorecon -R /var/www/html

AppArmor (Ubuntu)

# show status
aa-status
# view nginx profile
cat /etc/apparmor.d/usr.sbin.nginx
# reload profiles after edit
systemctl reload apparmor

Summary

Core concepts

Three permission classes: owner (u), group (g), others (o).

Three bits per class: read = 4, write = 2, execute = 1.

Directory write permission controls creation/deletion of entries, independent of file mode. umask subtracts bits from the default 666/777 to produce the initial mode of new files/dirs.

Special bits – SUID (4xxx), SGID (2xxx), Sticky (1xxx).

ACLs provide fine‑grained per‑user or per‑group permissions beyond the traditional model.

Common command cheat‑sheet

# Change mode
chmod 755 file          # numeric
chmod u+x file          # symbolic
chmod -R 755 directory # recursive

# Change owner / group
chown user:group file
chown :group file       # only group
chown -R user:group dir # recursive

# View permissions
ls -la file
getfacl file            # ACL view

# ACL manipulation
setfacl -m u:alice:rw file
setfacl -m g:dev:rx dir
setfacl -m d:u:bob:rw dir   # default for new items
setfacl -b file              # remove all ACLs

# SELinux
getenforce
chcon -t httpd_sys_rw_content_t /var/www/html/uploads
semanage fcontext -a -t httpd_sys_content_t "/var/www/html(/.*)?"
restorecon -R /var/www/html

Learning recommendations

Focus on understanding the model rather than memorising numbers.

Experiment in a test environment: change modes, observe access results.

Pay attention to error messages – they often indicate the exact permission problem.

Apply the principle of least privilege to every service.

Record original permissions before changes; use getfacl backups for safe rollback.

Proper permission management is a cornerstone of Linux security and reliability. Consistent use of the techniques above prevents most production‑environment 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.

Linuxsecuritysysadminaclchmodchownfile-permissions
MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

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.