Linux ACL: setfacl, getfacl, and Permission Workflow on ext4 and xfs

POSIX ACLs extend owner/group/other permissions with per-user and per-group rules. On Linux, getfacl inspects ACLs and setfacl changes them on ext4 and xfs; GNU chmod has no +a syntax (that is macOS/BSD).

Published

Updated

Read time 12 min read

Reviewed byDeepak Prasad

Linux ACL: setfacl, getfacl, and Permission Workflow on ext4 and xfs
About POSIX ACLs extend owner/group/other permissions with per-user and per-group rules. On Linux, getfacl inspects ACLs and setfacl changes them on ext4 and xfs; GNU chmod has no +a syntax (that is macOS/BSD).
Tested on Ubuntu 25.04 (Plucky Puffin); acl 2.3.2; kernel 7.0.0-27-generic; ext4 with acl mount option
Package acl
Man page setfacl(1)
Privilege root / sudo for changes (getfacl works as user)
Distros acl package on ext4 and xfs (Ubuntu, Debian, RHEL, Fedora, SUSE).
Related guide

ACL — quick reference

Inspect (getfacl)

Read current ACL entries before changing permissions — safe on any file you can read.

When to use Command
Show full ACL including mask and defaults getfacl /path/to/file
Access ACL only (skip default entries) getfacl -a /path/to/dir
Default ACL only (directories) getfacl -d /path/to/dir
Show effective rights after mask limits getfacl -e /path/to/file
List ACLs under a tree getfacl -R /path/to/tree
Backup ACLs for restore later getfacl -R /path > acls.backup

Modify (setfacl)

Add or change named user/group entries without replacing the whole ACL.

When to use Command
Grant read to one user on a file sudo setfacl -m u:alice:r-- /data/report.txt
Grant traverse on a directory (list + enter) sudo setfacl -m u:alice:r-x /data/shared
Grant a group write on a file sudo setfacl -m g:developers:rw- /data/app.conf
Set mask explicitly (cap named user/group rights) sudo setfacl -m m::r-- /data/file
Replace entire ACL from one string sudo setfacl --set="u::rw-,g::r--,o::---" /data/file
Apply ACL changes down a directory tree sudo setfacl -R -m u:alice:r-- /data/tree
Dry-run — print what would change sudo setfacl --test -m u:alice:rwx /data/file

Default ACLs (setfacl -d)

Default entries apply only to directories and are inherited by new files and subdirectories.

When to use Command
New files in a dir inherit read for a user sudo setfacl -d -m u:alice:r-- /data/shared
Set access and default ACL in one command sudo setfacl -m u:alice:r-x -d -m u:alice:r-- /data/shared
Remove default ACL from a directory sudo setfacl -k /data/shared

Remove (setfacl)

Drop extended rules while keeping owner/group/other bits from chmod.

When to use Command
Remove one named user entry sudo setfacl -x u:alice /data/file
Remove one named group entry sudo setfacl -x g:developers /data/file
Strip all extended ACL entries sudo setfacl -b /data/file
Restore ACLs from a getfacl backup sudo setfacl --restore=acls.backup

Full replace (chacl)

Low-level tool that replaces the entire ACL in one shot — prefer setfacl for day-to-day edits.

When to use Command
Replace ACL with a declarative rule string sudo chacl "u::rw-,g::r--,o::---" /data/file
Remove all ACLs (reset to mode bits only) sudo chacl -B /data/file

Filesystem must support ACLs (ext4 with acl mount option, or xfs — both default on Ubuntu 25.04). ls -l shows a + after the mode when extended ACLs exist.


ACL — command syntax

setfacl synopsis from setfacl --help on Ubuntu 25.04 (acl 2.3.2):

text
setfacl [-bkndRLP] { -m|-M|-x|-X ... } file ...
  -m, --modify=acl        modify the current ACL(s) of file(s)
  -x, --remove=acl        remove entries from the ACL(s) of file(s)
  -b, --remove-all        remove all extended ACL entries
  -d, --default           operations apply to the default ACL
  -R, --recursive         recurse into subdirectories
      --set=acl           set the ACL, replacing the current ACL
      --restore=file      restore ACLs (inverse of getfacl -R)

getfacl reads the same entry format (u:alice:r--, g:developers:rw-, m::r--, d:u:alice:r-- for defaults). Changes are stored in the filesystem extended attribute system.posix_acl_access (and system.posix_acl_default on directories).


ACL — command examples

Essential Inspect ACLs with getfacl (baseline)

Before changing permissions, read what the kernel enforces. getfacl shows owner, group, mask, and any named users — more detail than ls -l.

Create a test file and view its ACL:

bash
echo "quarterly report" | sudo tee /tmp/acl-demo/report.txt > /dev/null
sudo chmod 600 /tmp/acl-demo/report.txt
getfacl /tmp/acl-demo/report.txt

Sample output:

text
# file: tmp/acl-demo/report.txt
# owner: root
# group: root
user::rw-
group::---
other::---

Only the three classic entries appear — no + in ls -l yet. This is the baseline before adding named users.

Essential Grant read access to one user (setfacl -m)

When chmod cannot give a second user read access without opening the file to everyone, add a named user ACL entry.

Grant read to nobody without changing owner or group:

bash
sudo setfacl -m u:nobody:r-- /tmp/acl-demo/report.txt
getfacl /tmp/acl-demo/report.txt
ls -l /tmp/acl-demo/report.txt

Sample output:

text
# file: tmp/acl-demo/report.txt
# owner: root
# group: root
user::rw-
user:nobody:r--
group::---
mask::r--
other::---
-rw-r--r--+ 1 root root 17 Jul  1 15:48 /tmp/acl-demo/report.txt

The + after the mode means extended ACLs are present. mask::r-- caps what named users and the owning group can actually use.

Essential Verify effective permissions as another user

Confirm the ACL works from the recipient's point of view — getfacl alone does not prove access.

Test read as nobody:

bash
sudo -u nobody cat /tmp/acl-demo/report.txt

Sample output:

text
quarterly report

If this fails, check the mask with getfacl -e — a permissive user entry can still be capped by mask::r--.

Common Default ACL on a shared directory (inheritance)

Access ACLs control the directory itself; default ACLs define what new files inside inherit. This is the usual pattern for team folders on ext4 or xfs.

Set access and default ACL on a directory:

bash
sudo mkdir -p /tmp/acl-demo/shared
sudo chmod 700 /tmp/acl-demo/shared
sudo setfacl -m u:nobody:r-x -d -m u:nobody:r-- /tmp/acl-demo/shared
getfacl /tmp/acl-demo/shared

Sample output:

text
# file: tmp/acl-demo/shared
# owner: root
# group: root
user::rwx
user:nobody:r-x
group::---
mask::r-x
other::---
default:user::rwx
default:user:nobody:r--
default:group::---
default:mask::r--
default:other::---

Create a new file inside and confirm inheritance:

bash
sudo touch /tmp/acl-demo/shared/newfile.txt
getfacl /tmp/acl-demo/shared/newfile.txt

Sample output:

text
# file: tmp/acl-demo/shared/newfile.txt
# owner: root
# group: root
user::rw-
user:nobody:r--
group::---
mask::r--
other::---

Default ACL does not retroactively change files that already existed — only new entries.

Common Remove one ACL entry (setfacl -x)

Revoke access for one user while keeping other ACL rules intact.

Remove the nobody entry from the report file:

bash
sudo setfacl -x u:nobody /tmp/acl-demo/report.txt
getfacl /tmp/acl-demo/report.txt
ls -l /tmp/acl-demo/report.txt

Sample output:

text
# file: tmp/acl-demo/report.txt
# owner: root
# group: root
user::rw-
group::---
mask::---
other::---
-rw-------+ 1 root root 17 Jul  1 15:48 /tmp/acl-demo/report.txt

The + can remain briefly until the last extended entry is gone; setfacl -b clears all extended entries at once.

Common Mask limits effective rights (getfacl -e)

A user entry may grant rwx but the mask can silently reduce effective access — a common troubleshooting surprise.

Set a wide user ACL with a tight mask:

bash
echo secret | sudo tee /tmp/acl-demo/mask-demo.txt > /dev/null
sudo chmod 600 /tmp/acl-demo/mask-demo.txt
sudo setfacl -m u:nobody:rwx,m::r-- /tmp/acl-demo/mask-demo.txt
getfacl -e /tmp/acl-demo/mask-demo.txt

Sample output:

text
# file: tmp/acl-demo/mask-demo.txt
# owner: root
# group: root
user::rw-
user:nobody:rwx	#effective:r--
group::---	#effective:---
mask::r--
other::---

#effective:r-- shows the kernel only allows read despite rwx on the user line. Raise the mask with sudo setfacl -m m::rwx FILE if write is intended.

Advanced Apply ACLs recursively (-R)

Large project trees sometimes need the same named-user rule on every file — -R walks the directory.

Apply read for nobody under the demo tree:

bash
sudo setfacl -R -m u:nobody:r-- /tmp/acl-demo
getfacl /tmp/acl-demo/shared/newfile.txt

Sample output:

text
# file: tmp/acl-demo/shared/newfile.txt
# owner: root
# group: root
user::rw-
user:nobody:r--
group::r--
mask::r--
other::r--

Use -R carefully on production trees — it touches every file. Pair with getfacl -R backup before bulk changes.

Advanced chacl replaces the entire ACL (advanced reset)

chacl is not incremental — each run replaces the whole ACL. Use it for a clean reset or a declarative policy string, not for small edits.

Inspect, then replace with chacl:

bash
getfacl /tmp/acl-demo/report.txt
sudo chacl "u::rw-,g::r--,o::---" /tmp/acl-demo/report.txt
getfacl /tmp/acl-demo/report.txt

Sample output after chacl:

text
# file: tmp/acl-demo/report.txt
# owner: root
# group: root
user::rw-
group::r--
mask::rw-
other::---

Named user entries from earlier setfacl runs are gone. For day-to-day work, prefer setfacl -m and setfacl -x. To strip all extended ACLs, setfacl -b or chacl -B also work.

Clean up lab files when finished:

bash
sudo rm -rf /tmp/acl-demo

ACL — when to use / when not

Use ACLs (setfacl/getfacl) when Use something else when
  • Multiple users need different permissions on the same file or directory
  • You cannot change owner or group but must grant access to one extra account
  • A shared directory on ext4 or xfs needs inherited defaults for new files
  • ls -l shows + or getfacl already lists named users
  • NFS or Samba exports rely on POSIX ACLs on the backing filesystem
  • Owner/group/other bits are enough → chmod
  • Wrong owner or primary group → chown
  • Filesystem has no ACL support (e.g. some FAT mounts) → reformat or use different mount
  • You are on macOS and typed chmod +a — on Linux use setfacl instead
  • Centralized identity (LDAP/AD) owns authorization → directory policy, not local ACL hacks

setfacl vs chmod vs chacl

setfacl / getfacl chmod chacl
Role Per-user/group ACL entries Owner, group, other mode bits Full ACL replace
Incremental edits Yes (-m, -x) Yes (mode digits) No — overwrites all
Default inheritance Yes (-d) on directories No Yes (in full ACL string)
Inspect getfacl ls -l, stat getfacl / chacl -l
Linux chmod +a N/A — use setfacl GNU chmod has no +a (macOS/BSD syntax) N/A

Start with chmod and chown. Reach for setfacl when the classic triple is too coarse.


Nearby tools for the same permission workflow — mode bits, ownership, and extended ACLs.

Command One line
getfacl Read ACL entries (this page)
umask Default mode mask for new files

Browse the full index in our Linux commands reference.


ACL — interview corner

Practice these before exams or standups. Each card explains the idea in plain language, then ends with a short answer you can say aloud.

What is a POSIX ACL in Linux?

A POSIX ACL extends the classic owner/group/other model. Instead of only three permission classes, you can attach rules for named users and named groups on a single file or directory.

The kernel still stores base mode bits (what chmod sets), but when ACLs exist it also reads extended attributes — on ext4 and xfs you will see system.posix_acl_access. ls -l adds a + after the mode when those extended entries are present.

bash
getfacl /data/shared/report.txt

Sample lines:

text
user::rw-
user:alice:r--
group::r--
mask::r--
other::r--

A strong answer is:

"POSIX ACLs let me grant per-user or per-group access on one inode without changing owner or opening the file to everyone. On Linux I inspect with getfacl and change with setfacl on ACL-capable filesystems like ext4 and xfs."

What does the ACL mask do?

The mask (mask::) is the ceiling for named users, named groups, and the owning group entry. Even if user:bob:rwx is listed, effective access is the intersection of that entry and the mask.

bash
getfacl -e /data/file

When the mask is tight you may see:

text
user:bob:rwx	#effective:r--
mask::r--

That #effective:r-- line is what the kernel actually enforces. Fix it by raising the mask (setfacl -m m::rwx) or by letting setfacl recalculate the mask (omit -n).

A strong answer is:

"The mask caps effective rights for named users, named groups, and the owning group — I use getfacl -e to see effective permissions when access looks wrong despite a permissive user line."

What is the difference between access ACL and default ACL?

An access ACL applies to the file or directory itself — who can read, write, or traverse it right now.

A default ACL exists only on directories. It does not change existing files; it tells the kernel which ACL entries to copy onto new files and subdirectories created inside.

bash
sudo setfacl -m u:alice:r-x -d -m u:alice:r-- /data/shared
getfacl /data/shared

Look for lines starting with default: in getfacl output. Missing defaults are why a user can access the folder but not files created by someone else.

A strong answer is:

"Access ACL controls the object itself; default ACL on a directory defines inheritance for new children only — I set both when building a team folder on ext4 or xfs."

When do you use setfacl vs chacl?

setfacl is for everyday administration: add one user (-m), remove one entry (-x), strip everything (-b), or set directory defaults (-d). Each call changes only what you specify.

chacl replaces the entire ACL from a single rule string — closer to a reset or generated policy. A second chacl run does not merge; it overwrites again.

Task Tool
Grant one user read setfacl -m u:alice:r-- file
Remove one user setfacl -x u:alice file
Declarative full ACL chacl "u::rw-,g::r--,o::---" file
Strip extended ACLs setfacl -b or chacl -B

A strong answer is:

"I use setfacl for incremental ACL edits and chacl only when I need to replace the whole ACL or reset to a known template — chacl is not safe for small tweaks."

Does Linux chmod support +a for ACLs?

No on GNU/Linux. chmod +a is macOS/BSD syntax for attaching ACL rules. Linux distributions ship POSIX ACL tools in the acl package instead.

bash
chmod +a

On Ubuntu 25.04 that fails — there is no +a operand. The portable Linux equivalent is:

bash
sudo setfacl -m u:alice:r-- /path/to/file
getfacl /path/to/file

Keep using chmod for u+rw, g+r, and numeric modes; use setfacl when you need a named principal.

A strong answer is:

"GNU chmod on Linux does not implement chmod +a — that is BSD/macOS. I use setfacl -m for per-user ACL entries and getfacl to verify them on ext4 or xfs."

Do ACLs work on ext4 and xfs?

Yes, when the filesystem is mounted with ACL support — default on Ubuntu for both ext4 and xfs.

Check ext4 mount options:

bash
tune2fs -l /dev/ROOT_DEVICE | grep "Default mount options"

You should see acl in the list. On xfs, ACLs are part of the standard feature set. tmpfs and other filesystems may lack ACL support; setfacl then fails with Operation not supported.

A strong answer is:

"ext4 and xfs on Ubuntu support POSIX ACLs out of the box — I confirm with tune2fs or mount options if setfacl returns operation not supported."


Troubleshooting

Symptom Likely cause Fix
Operation not supported Filesystem or mount without ACL Use ext4/xfs; check mount for noacl
User still denied after setfacl -m u:user:rwx Mask too restrictive getfacl -e FILE; raise mask with setfacl -m m::rwx
+ in ls -l but no extra users listed Leftover mask or empty extended set setfacl -b FILE to clear extended ACL
New files lack expected ACL No default ACL on parent directory setfacl -d -m … on the directory
setfacl: Option -m: Invalid argument Bad user/group name Use getent passwd user / getent group grp
chmod +a fails on Linux BSD-only syntax Use setfacl -m instead
chacl removed wanted entries Full replace semantics Use setfacl -m / -x; backup with getfacl -R first

References

Rohan Timalsina

is a technical writer and Linux enthusiast who writes practical guides on Linux commands and system administration. He focuses on simplifying complex topics through clear explanations.