Migrate to RunxBuild and earn up to $50 in hosting credit on your first deposit.

Calculate your savings
unxBuild

Change the Owner of a Directory in Linux: chown, -R, and the Mistakes That Hurt

Sean

Platform Writer

Aug 26, 2026
8 min read

sudo chown -R username:groupname /path/to/directory changes ownership of a directory and everything inside it. The -R is what makes it useful and what makes it dangerous — pointed at the wrong path, it will happily rewrite ownership across your entire system, and there is no undo.

Change the Owner of a Directory in Linux: chown, -R, and the Mistakes That Hurt

Ownership problems usually show up as permission denied on something you can plainly see. A web server cannot write to an uploads directory, a deploy cannot replace a file, a service will not start because it cannot read its own config.

The command to fix it is short. The part worth spending a minute on is confirming you are pointing it at the right thing, because chown -R is one of the few commands that can render a machine unbootable from a single typo.

Table of contents

The command and its forms

chown user directory              # owner only, group unchanged
chown user:group directory        # owner and group
chown :group directory            # group only
chown user: directory             # owner, group set to user's login group
chown -R user:group directory     # recursive

Note the difference between chown user: and chown user. The trailing colon also sets the group to that user’s default group, which is usually what you meant. Without it, the group is left alone — a frequent cause of a fix that only half works.

Check what you have before and after:

ls -ld /var/www/myapp
# drwxr-xr-x 5 www-data www-data 4096 Aug 26 10:14 /var/www/myapp

-d is important — without it, ls -l lists the directory’s contents rather than the directory itself, which is a different question.

chgrp exists for group-only changes and is equivalent to chown :group. Either is fine; chown is one less command to remember.

Confirm the target before adding -R

The habit that prevents the bad outcome, and it costs one command:

ls -ld /var/www/myapp                        # is this the right path?
find /var/www/myapp -maxdepth 1 | head -20   # what is actually in it?
find /var/www/myapp | wc -l                  # how many files am I touching?

If the count is far larger than expected, stop. A recursive chown on 400,000 files is either exactly right or a serious mistake, and the number tells you which before you find out the hard way.

Three specific traps:

  • A trailing slash on a variable. chown -R www-data:www-data "$DIR/" with DIR unset expands to chown -R www-data:www-data /. Guard it: [ -n "$DIR" ] && chown -R www-data:www-data "$DIR".
  • A stray space. chown -R user: /var/www and chown -R user:/var/www are different commands, and the second is a parse error rather than the disaster — but chown -R user /var /www quietly does two directories.
  • Symlinks. By default chown -R follows the ownership of symlinks themselves, not their targets. -L makes it traverse into symlinked directories, which can walk straight out of the tree you meant to change.

Leave -L alone unless you have a specific reason and have checked where the links point.

Recovering from a chown you should not have run

Worth reading before you need it, because the answer is genuinely limited.

There is no undo. chown does not record previous ownership anywhere. If you ran it recursively on /, /usr, or /etc, sudo will typically stop working (it requires root-owned binaries with the setuid bit), and much of the system will refuse to start.

What can help, in order:

  1. Package manager verification. On Debian and Ubuntu, dpkg --verify reports ownership mismatches against what packages declared. On RHEL family, rpm -Va does the same and rpm --setugids <package> restores them.
  2. A reference file. If one directory still has correct ownership, chown --reference=/known/good /path/to/fix copies it.
  3. A snapshot or backup. The only complete answer for anything outside package-managed paths.
# RHEL family: restore ownership for every installed package
sudo rpm -qa | xargs -n1 sudo rpm --setugids

None of this recovers ownership of files packages do not know about — your application data, your uploads, your home directory. Snapshots are the real safety net, which is an argument for taking one before any bulk permission change on a machine that matters.

Ownership versus permissions

These get conflated and they answer different questions. Ownership says who; permissions say what they may do.

chown www-data:www-data /var/www/uploads   # who owns it
chmod 755 /var/www/uploads                 # what may be done to it

Changing the owner does not grant access on its own — if the mode is 700 and owned by someone else, you still cannot get in. Most real fixes need both, and the usual shape for a web application is:

sudo chown -R www-data:www-data /var/www/myapp
sudo find /var/www/myapp -type d -exec chmod 755 {} \;
sudo find /var/www/myapp -type f -exec chmod 644 {} \;

Directories need the execute bit to be traversable; files do not need it at all. Using chmod -R 755 on everything makes every file executable, which is sloppy rather than catastrophic — the find version above is the correct one.

Two mechanisms that avoid recursive chown entirely, and are better where they apply:

  • setgid on a directorychmod g+s /var/www/shared makes new files inherit the directory’s group, so a shared directory stays consistent without repeated fixes.
  • ACLssetfacl -m u:deploy:rwx /var/www/myapp grants one extra user access without changing ownership at all.

The container case, where UIDs stop matching

Bind-mounting a host directory into a container is where ownership gets genuinely confusing, because the two sides do not share a user database.

Linux stores ownership as numeric IDs. Names are a lookup, performed separately on each side. So a file owned by UID 1000 shows as your username on the host and as whatever user happens to be 1000 inside the container — or as a bare 1000 if nothing matches.

ls -n /var/www/myapp        # show numeric IDs instead of names
docker exec mycontainer id  # what the container process runs as

If those numbers disagree, you get permission denied on a file that looks correctly owned from both sides.

The fix is to align the IDs rather than to chown the mount repeatedly:

ARG UID=1000
ARG GID=1000
RUN groupadd -g $GID app && useradd -u $UID -g $GID -m app
USER app

Build with --build-arg UID=$(id -u) and the container’s user matches the host’s. Running chown -R on a mounted volume after every start is the alternative, and it is slow, repetitive, and modifies the host’s files as a side effect.

How this fits the rest of the stack

Ownership problems are a symptom of a deployment model where the same files are touched by several identities — your login, a deploy script, the web server process, a container user — and nothing coordinates them. Each fix works until the next actor writes a file.

That coordination problem largely disappears when the platform owns the runtime. RunxBuild builds from your repository and runs the service with a consistent identity, with persistent storage attached to the service rather than bind-mounted from a host you also administer — so there is no host UID to reconcile and no post-deploy chown step. If you want to see what a service with storage and a managed database costs together, the RunxBuild hosting calculator itemises them.

Useful related references:

FAQ

How do I change the owner of a directory and everything in it?

sudo chown -R user:group /path/to/directory. Check the path with ls -ld and count the files with find /path | wc -l before running it — a recursive chown on far more files than you expected is a warning worth heeding, because there is no undo.

What is the difference between chown user and chown user:?

chown user changes the owner and leaves the group untouched. chown user: also sets the group to that user’s default login group, which is usually what people intend. Forgetting the colon is a common reason a permission fix only half works.

Can I undo a chown command?

Not directly — chown records no previous state. On package-managed paths, rpm --setugids on RHEL family or dpkg --verify on Debian can restore declared ownership. For application data and home directories, only a snapshot or backup recovers it.

Why does chown not fix my permission denied error?

Because ownership and permissions are separate. Owning a file with mode 700 owned by another user still denies you access. You usually need both: chown for who owns it, then chmod for what may be done to it. Directories also need the execute bit to be traversable.

Why do file permissions break with Docker bind mounts?

Linux stores ownership as numeric UIDs and resolves names separately on each side, so UID 1000 can be your user on the host and a different user inside the container. Align them by creating the container user with your host UID via a build arg, rather than running chown on the volume after every start.

#change owner of directory linux#chown#linux#permissions#file ownership