chown and chgrp: Changing Ownership
Every file and directory on a Linux system belongs to exactly one user (the owner) and one group. That ownership determines whose permission bits apply when someone tries to read, write, or execute the file. chown changes a file’s owner (and optionally its group) in one command, while chgrp changes only the group. Getting ownership right is essential for web servers, shared project directories, deployment scripts, and any system where more than one account touches the same files.
Overview: How Ownership Works
Internally, the kernel does not store ownership as text like root or www-data. Every file’s inode stores two numbers: a UID (user ID) and a GID (group ID). The files /etc/passwd and /etc/group map those numbers to human-readable names. When you run ls -l, the ls command looks up the UID and GID for each file and prints the matching names — but the raw filesystem data is just two integers. This is why you can delete a user’s account, leave their files behind, and later see a bare number instead of a name in ls -l output: the name-to-number mapping is gone, but the number on disk never changed.
Ownership matters because Linux permission bits are split into three sets: owner, group, and other (see the earlier lesson on permission bits). Which set applies to a given process depends entirely on whether that process’s user matches the file’s owner UID, whether it belongs to the file’s group GID, or neither. Change the owner or group, and you change which permission bits govern who can do what — without touching the rwx bits themselves.
Changing a file’s owner is a privileged operation: only root (or a process with the CAP_CHOWN capability) can do it, which is why every chown example that changes ownership needs sudo. This restriction exists so that an ordinary user cannot hand off a file they own to another account — if that were allowed, a user could dodge disk quotas by giving their large files to someone else, or trick another user into owning (and being blamed for) malicious content. Changing a file’s group, however, is less restricted: the file’s current owner can change its group to any group they themselves belong to, without sudo. In practice, most system administration is done as root via sudo anyway, so you’ll see sudo in front of nearly every chown and chgrp example.
Syntax
The general forms are:
chown [OPTION]... [OWNER][:[GROUP]] FILE...
chgrp [OPTION]... GROUP FILE...
For chown, the OWNER:GROUP argument is flexible:
chown alice file— changes only the owner toalice, leaves the group untouched.chown alice:staff file— changes the owner toaliceand the group tostaffin one step.chown :staff file— changes only the group (the leading colon with no owner before it), equivalent tochgrp staff file.chown alice: file— changes the owner toaliceand sets the group toalice‘s primary group.
Common options for both commands:
| Option | Meaning |
|---|---|
-R, --recursive |
Apply the change to a directory and everything inside it, recursively. |
-v, --verbose |
Print a line for every file whose ownership is changed (or attempted). |
-c, --changes |
Like -v, but only report files that actually changed. |
-h, --no-dereference |
Change the symbolic link itself, not the file it points to (the default follows the link). |
--reference=RFILE |
Copy the owner (and group, for chown) from an existing file RFILE instead of naming one directly. |
--from=OWNER:GROUP |
(chown only) Only change files currently owned by the given owner/group — useful as a safety check before a bulk change. |
Examples
Example 1: Changing the owner of a single file
A file was created as root but needs to be served by the www-data user that runs the web server:
ls -l /var/www/html/index.html
sudo chown www-data /var/www/html/index.html
ls -l /var/www/html/index.html
Output:
-rw-r--r-- 1 root root 512 Aug 3 10:15 /var/www/html/index.html
-rw-r--r-- 1 www-data root 512 Aug 3 10:15 /var/www/html/index.html
The first ls -l shows the file owned by root. After sudo chown www-data ..., the second ls -l shows the owner field changed to www-data. The group (root) was untouched because we didn’t specify one.
Example 2: Changing owner and group together
Now set both the owner and the group to www-data in a single command, using the colon form:
sudo chown www-data:www-data /var/www/html/index.html
ls -l /var/www/html/index.html
Output:
-rw-r--r-- 1 www-data www-data 512 Aug 3 10:15 /var/www/html/index.html
Both the owner and group columns now read www-data. This is the standard pattern for handing a file to a service account that should fully control it.
Example 3: Recursive ownership change on a deployment directory
A deploy script just unpacked a release as root, but the whole site should belong to a deploy user while staying readable by the www-data group:
sudo chown -Rv deploy:www-data /var/www/html
Output:
changed ownership of '/var/www/html/index.html' from root:root to deploy:www-data
changed ownership of '/var/www/html/assets' from root:root to deploy:www-data
changed ownership of '/var/www/html/assets/style.css' from root:root to deploy:www-data
The -R flag walks into every subdirectory and file under /var/www/html, applying the same owner and group to each one. The -v flag makes chown report every change it makes, which is invaluable for confirming a recursive change touched what you expected before you move on.
Example 4: Sharing a directory with a group using chgrp
Several developers need write access to a shared project directory, so it’s handed to a developers group instead of a single user:
sudo chgrp -R developers /srv/projects/app
ls -ld /srv/projects/app
Output:
drwxrwxr-x 6 root developers 4096 Aug 4 09:00 /srv/projects/app
chgrp only ever touches the group field, leaving the owner (root) alone. Combined with group write permission (rwx for group, as shown here), every member of developers can now read, write, and enter this directory.
How It Works Step by Step
When you run sudo chown deploy:www-data /var/www/html/index.html, several things happen in sequence:
- The shell parses the command line and finds the
sudoprogram, which checks whether your user is allowed to run commands asroot(via/etc/sudoers), prompts for your password if needed, and then executeschownwith root privileges. chownresolves the namesdeployandwww-datato numeric UID and GID values by reading/etc/passwdand/etc/group(or whatever name service is configured via NSS).chowncalls thechown(2)system call, passing the target path and the resolved UID/GID. The kernel checks that the calling process has theCAP_CHOWNcapability (which root has), then updates the UID and GID fields stored in the file’s inode.- On a journaling filesystem like ext4, this metadata change is written to the journal before being committed to the main filesystem structures, so an unexpected power loss mid-write won’t corrupt the ownership data.
- The next time any program (like
ls) reads that file’s metadata, it sees the new UID/GID and again performs a name lookup through NSS to displaydeployandwww-datainstead of raw numbers.
With -R, chown repeats steps 2–3 once for every file and directory it finds while recursively walking the directory tree, which is why a recursive chown on a large tree can take a noticeable amount of time — it is issuing one system call per file, not one call for the whole tree.
Common Mistakes
Mistake 1: Forgetting sudo
Changing an owner is a privileged operation. Without sudo, it fails outright:
$ chown www-data /var/www/html/index.html
chown: changing ownership of '/var/www/html/index.html': Operation not permitted
The fix is simply to run it with elevated privileges:
sudo chown www-data /var/www/html/index.html
Mistake 2: Forgetting the colon when you only mean the group
It’s tempting to write chown developers file when you actually want to change the group. But without a leading colon, chown reads developers as the new owner, not the group — and if no user named developers exists, it fails outright:
$ chown developers /srv/projects/app
chown: invalid user: 'developers'
Use a leading colon to target the group only, or use chgrp, which makes the intent explicit:
sudo chown :developers /srv/projects/app
Mistake 3: Recursive chown on the wrong path
Because -R silently walks every file under the path you give it, a typo in the path can rewrite ownership across the entire filesystem. Running the following as root is destructive and can leave a system unbootable, since core system files would end up owned by the wrong account:
sudo chown -R www-data:www-data /
Always double-check the path before adding -R, and scope it as narrowly as possible:
sudo chown -R www-data:www-data /var/www/html
Best Practices
- Use
-vor-cwith recursive changes so you have a record of exactly what was modified, especially when scripting deployments. - Prefer the colon form (
owner:group) over the older dot form (owner.group); the colon is unambiguous even if a username happens to contain a dot. - Use
--from=OWNER:GROUPas a safety check when bulk-changing ownership, so files that don’t match your expectation are left alone instead of silently rewritten. - Prefer service accounts (like
www-dataor a dedicateddeployuser) over personal accounts for files served by long-running processes, so ownership doesn’t depend on any one person’s account existing. - Double-check the target path before combining
chownwith-R— there is no undo, and a wrong path can affect far more files than intended. - Use group ownership (
chgrporchown :group) plus group permission bits to share access among a team, rather than making files world-writable.
Practice Exercises
- Create a file with
touch ~/notes.txt. Check its owner and group withls -l, then usechgrpto change its group to a group you belong to (see your groups with thegroupscommand). Confirm the change withls -lagain. - Imagine a CI pipeline just deployed a release to
/opt/myappwhile running asroot, but the app should run as a dedicatedmyappservice user with groupmyapp. Write the single recursivechowncommand that fixes ownership for the whole directory tree, with verbose output enabled. - You need to let everyone in the
designgroup edit files under/srv/shared/assetswithout becoming the owner of each file. Work out which command(s) set the group todesignand which permission bits (from the earlierchmodlesson) you’d also need so group members can write to it.
Summary
- Every file has a numeric owner (UID) and group (GID); names shown by
ls -lare just a lookup through/etc/passwdand/etc/group. chownchanges a file’s owner and, optionally, its group in one command using theowner:groupsyntax.chgrpchanges only the group, and is equivalent tochown :group.- Changing an owner requires root privileges (
sudo); changing a group only requires that you own the file and belong to the target group. -Rapplies the change recursively through a directory tree — always verify the path first, since there’s no undo.-v/-creport exactly what changed, which is essential for auditing bulk ownership changes in scripts.
