Linux chmod Command Made Easy (Complete Guide)

The chmod command on Linux is used to manage permissions for files and directories. Let's break down how it works, with simple explanations and examples.

It's easier to understand through practice. So we'll jump into a Linux terminal, and see the commands we need to use. Screenshots will be provided to show you the effects of each command.

This guide will focus on how to use the chmod command. But, if you need it, we also have a guide about the theory of how file and directory permissions work on Linux.

How chmod Works

The chmod command has a pretty intuitive way we can interact with it. Although a command like chmod g+rw file.txt might look slightly weird, here's how it works.

After we write chmod we specify who we want to change permissions for:

  • Is it for the user that owns this file? Then we type the u letter.
  • Is it for the group that owns this file? Then we type the g letter.
  • Is it for other users? "Others" meaning anyone that is not the owner of that file, and not part of the group that owns that file. Then we type the o letter.
  • Is it for everyone (the user that owns the file, the group, and also other users)? Then we can use the a letter. Think of a as meaning all.

Same applies if chmod works with a directory, instead of a file.

Pretty simple, right?

  • u for user.
  • g for group.
  • o for others
  • a for all of the above. In other words, a is equal to ugo.

In our example, we want to work with group-level permissions. That's how we get to the first part in our chmod g+rw file.txt command:

chmod g

Then there's the + sign we used in chmod g+rw file.txt. What is this about?

Well, after we tell chmod who we want to change permissions for, we tell it what we want to do. And we have 3 choices here:

  1. Add permissions on top of the pre-existing permissions. We do that with +.
  2. Remove permissions from the pre-existing permissions. We do that with -.
  3. And set permissions to exact values. Meaning we overwrite the old permissions and set to something else instead. We do that with =.

In our example, we want to keep old permissions, and add something extra on top. That's how we got to:

chmod g+

Otherwise said, for the group-level permissions, we want to add extra permissions.

Now the last part chmod expects: what permissions do we want to add, remove? Or what exact permissions we want to set here (if we use the = sign). In this part we can use:

  • The r letter for read permission.
  • w for write permission.
  • And x for execute permission.

That's how we get to:

chmod g+rw

So g+rw means: For the g group-level permissions, we + add something on top, rw read, and write.

If we'd want to add only the read permission (but no write), then we'd type:

chmod g+r

If we'd want to add all of them – read, write, execute – we'd run:

chmod g+rwx

And if we'd want to add r and x permissions for the u user, and the g group, we could also enumerate these ug letters as well:

chmod ug+rx

Stuff like ugo works too, to change permissions for all three sets. Or go for group, and others.

Any combination we want, we can add the letters in their respective place. "Who" before the +, - or = signs. And "what" permissions after those signs.

Finally, after we choose what we want to do with the permissions, we specify the name of the file or directory we want to change. Here, we can use a relative path like file.txt, if the file is in our current directory:

chmod g+rw file.txt

Or we can use the full path to a file, if the file is in some other place (like the /home/alex/ directory):

chmod g+rw /home/alex/file.txt

And, of course, the same applies if we want to change permission for a directory. Relative path to a directory called project can be typed like this:

chmod g+rw project

If project is a directory in our current path.

Or the full path to this directory, if it's located in /home/alex can be typed like this:

chmod g+rw /home/alex/project

We can only change permissions if our current user owns this directory, or file. If our current user does not own them, we can run the same command with administrative root privileges, by adding sudo in front.chmod g+rw /home/alex/project becomes:

sudo chmod g+rw /home/alex/project

And speaking of directories, we can also make chmod change permissions recursively. A fancy way of saying: It will change permissions on the directory itself, but also all the stuff it contains. All the files it has, all the subdirectories, all the files in those subdirectories, everything. But that's a special use case that deserves some attention, so we'll discuss it in detail in a later section here.

Now let's dive deeper into these three ways to change permissions (add, remove, set exactly to). So we can see when we might pick each option, why, and what the effect is.

By the way, there's a fourth way to change permissions with chmod: By using octal values. Where instead of specifying permissions with the ugo, -+= signs, and rwx letters, we specify them with numbers like 755, 644, or something similar.

Three Ways to Change Permissions with the chmod Command

The three ways we'll explore here are:

  1. How to add permissions with chmod, with the + operator.
  2. How to remove permissions with chmod, with the - operator.
  3. And how to set permissions to exact values, with the = operator.

Add Permissions with chmod

There will be times when we'll want to make small changes to already existing permissions. Where we might think something like this:

Ok, this file / directory already has most of the correct permissions. But I just want to add this tiny little change on top of the existing permissions.

Maybe the group that owns that file already has read permissions. But we want to also add write permissions for the group. In that case, we'd run a command like this:

chmod g+w name_of_file_or_directory

Here's an example. We run ls -l list.txt to see current permissions of a file called list.txt. And we see this:

-rw-r--r-- 1 alex lxd 35 Mar 30 12:32 list.txt

Note how the second set of permissions (for the group) is r--. Which means the group (lxd in this case) can read this file. But the group has no write (or execute) permissions.

So we come along and say "Ok, let's add write permissions for the group here". All we need to do is run:

chmod g+w list.txt

And the w write permission pops up in the right spot. Also note that r, that existed before in the group-level permissions, remains unchanged. Same for the rw- permissions for the user that owns the file, and r-- for the other users.

Let's check another use case. Look at permissions for this file, called for.sh:

See the problem? A script is a file with instructions, and commands inside. And users should be able to execute it. But no one can do that yet, because the x permission is non-existent. If we try to run it:

./for.sh

We get an error:

As expected, with no x for the user, no x for the group, and no x for other users.

But the rest of the permissions look right:

  • The user that owns this file can read it, and write to it: rw-.
  • The group can do the same: rw-.
  • Other users can only read it: r--. No write permissions for others, which again, seems right. If it's a script that only we, the owners of the file want to be able to modify.

So the logic is the same here:

Most permissions look right. I just need to make a small change and add something on top.

Another good spot for the + operator of chmod. Which will keep the pre-existing rw- and r-- permissions, but add some x in some spots.

Now who do we want to allow to execute this script? If it's only the user that owns it, we'd run a chmod u+x command. But let's say we want to allow everybody to do this: The user that owns the file, the group that owns it, and other users. In that case, we could enumerate all of these with ugo. Which means we could run this command:

chmod ugo+x for.sh

And bam! The file looked like this before our change:

And now it looks like this:

x execute permission was added for the user, group, and others.

And we can run the script now:

./for.sh

But a shorter way to add permissions for everyone is to use a (all) instead of ugo. So these commands do the same thing, but the second is shorter to write:

chmod ugo+x for.sh
chmod a+x for.sh

And, in fact, there's even a shorter way to write this, as simply chmod +x for.sh. But I do not recommend omitting the ugoa letters that come before the +-= operators. Because it can lead to a mistake further down the line.

What mistake? When we want to make some recursive changes. And instead of chmod -R (capital R for recursive) we use a lowercase r. And write it as chmod -r. Which can happen, as other Linux commands do indeed use a lowercase r to make recursive changes. So we could understandably use the incorrect letter here. And depending on what we write after it, we'll either get an error (best-case scenario) or make the wrong changes, removing read permissions.

While chmod -r might lead to unexpected results, chmod a-r should offer consistent (and expected) results.

Remove Permissions with chmod

For the previous script file, for.sh, we might be thinking:

Wait a second. This is in Alex's personal directory. There's no reason why other users should be able to execute it. Or even read it.

Which is correct. We'd want to add x execute permissions for everybody, only for files that should be globally accessible. As is the case for most programs in the /bin directory, that every user on a Linux machine should be able to access and execute. But for a file in the personal home directory of a user? Usually not necessary.

This means we arrive in the situation where most permissions here are correct, but we want to remove just a few. A good scenario for chmod's - remove operator.

So what's wrong here?

The last part, r-x. We don't want others to be able to read, or execute this file. That means: For o others - remove the r read and x execute permissions. A simple o-rx, and we arrive at this command:

chmod o-rx for.sh

And just like that, job done. No more read and execute permissions for the third set (permissions for others):

Set Permissions to Exact Values with chmod

It seems like the + and - operators of chmod have us covered. When would we need the = sign to set permissions to exact values? Or another way to look at it: Overwrite old permissions with a new set of permissions. Well, here's just one possible scenario.

Let's imagine we do want to make this script globally accessible. We could move it to a directory like /usr/local/bin/, since every user has access to that location. But, first, we need to get the permissions right. And let's imagine there's a problem:

Somehow this file has permissions -wx for the other users. They can execute the script, which looks alright. But they can also write / modify this file? This doesn't look right. Also, they have no read permissions. How will they execute the script if they can't read it? Let's fix this.

But hmm... notice one small problem. We need two actions for this fix:

  1. Remove the w write permission.
  2. And add the r read permission.

Which means we'd need to run two commands:

  1. chmod o-w for.sh
  2. chmod o+r for.sh

Well, we can avoid this, and do it in a single action by using the = operator. Since we know we want to set the permissions for the o other users to = exactly r read and x execute:

chmod o=rx for.sh

The permissions before we ran our command:

And the permissions after we run our command:

Problem fixed with a single command!

So + and - are non-destructive. They keep what was there before, and only add, or remove what we specify. But = is destructive. It overwrites old permissions with new permissions that we specify. Which sometimes might be a desirable outcome, as we saw here.

Notice we used o=rx. Meaning we told chmod: "For others, set permissions to exactly read, and execute". We didn't tell it what to do with the existing w write permission. However, it removed the write permission! It set permissions to exactly rx, what we specified. What isn't specified after the = operator is removed.

Of course, in this case, it was desired to act this way. And that's usually the case if we need the = "set exactly to" operator. If we tell it to set something to exactly the read permission, then only read will be active in that spot, nothing else.

But one other important thing to notice:

It did not interfere with permissions for u the user that owns this file, or g the group. So, in this way, = is non-destructive. It only changes stuff in the set(s) we specify: User, group, or others. Which, of course, is also true for + and -.

Another cool use case for the = operator is when we want to remove all permissions from a set.

For example, if we want o others to have absolutely no permissions, we can remove them all with a command like this:

chmod o= for.sh

We basically told chmod: "Set permissions for o others to exactly nothing." Since we specified no permissions after =. Just make sure to add a space after the = sign (before typing the file or directory name).

Result of chmod o= for.sh:

All permissions removed from the third set of permissions for others.

Of course, we could achieve the same thing with:

chmod o-rwx for.sh

But this is just slightly faster to write:

chmod o= for.sh

Set Separate Permissions for User, Group, and Others (With One Command)

Up to this point we discussed various ways to change the same permissions for certain sets. For example, to add the read and write permissions for user, and group, we'd use a command like this:

chmod ug+rw file_name

But what if we're in this situation?

The file for.sh has no permissions enabled. Now imagine we want to add the following:

  • The user should be able to read, write, and execute this file: u+rwx.
  • The group should be able to only read, and write: g+rw.
  • Others should be able to just read: o+r.

To set these permissions in different ways for users, group, others, all we need to do is just add a , comma between each set. There should be no spaces between the commas and the letters before, and after.

So:

  1. u+rwx
  2. g+rw
  3. o+r

Becomes: u+rwx,g+rw,o+r

Which means the command we would run is this:

chmod u+rwx,g+rw,o+r for.sh

And we can see the expected result: rwxrw-r-- . That is:rwx for user, rw for group, r for others.

So, to reiterate, a command like this changes permissions in the same way for user, group, others:

chmod ugo+rw name_of_file

It adds the same r and w for user, group, and others.

But a command like this makes different changes for the user, group, and others:

chmod u=rwx,g=rw,o=r

It sets user permissions to rwx, group permissions to rw, and other permissions to r.

Note that we can also specify different operations for each set. For example, we could tell chmod to + add some permissions for the user, remove - some for the group, and = set exactly to some values for others:

chmod u+x,g-x,o=r name_of_file

Use Octal Values Like 755, or 644 with the chmod Command

When we want to adjust permissions just slightly, working with the ugoa letters, rwx, and +-= operators might be convenient. Something like chmod u+w file.txt does the job rather quickly.

But when we need to set different permissions for the user, group, and others, to some exact values, this way of working with chmod can become inconvenient. Especially if we need to do this multiple times, for multiple files, and directories.

Imagine we want to set permissions for a file to exactly:

  • rwx for the user.
  • rw for the group.
  • r for others.

If we'd work with the same file as before, called for.sh, the "classic" command we'd run is:

chmod u=rwx,g=rw,o=r for.sh

But with octal values, this becomes much simpler, and easier to write:

chmod 764 for.sh

It does the same thing as the command above it. Otherwise said, these commands are equivalent:

chmod u=rwx,g=rw,o=r for.sh
chmod 764 for.sh

Here's a before and after screenshot:

See? chmod 764 for.sh has the same effect we'd expect from chmod u=rwx,g=rw,o=r for.sh. It set permissions to rwxrw-r--.

If you want to find out how to calculate octal values to pass to the chmod command, see this blog about how file and directory permissions work on Linux. And jump to the section where octal values are discussed.

And here's a tip on how to learn permissions expressed in octal values right at the command line! Every time you change permissions, add the -v verbose option to the chmod command. Add this before the permission specifications. Example:

chmod -v u=rwx,g=rw,o=r for.sh

This will make the command display what it's doing. But, more importantly, it will also show permissions in octal values. Note how we can easily see that 0764 is equivalent to rwxrw-r--.

The first 0 is for special permissions like SETUID, SETGID, and sticky bit. 0 means none of these special permissions are used (which is often the case). So if the first digit is 0 we can consider 0764 to be 764.

We'll discuss special permissions later on.

Use chmod Recursively – Change Permissions for Entire Directory and its Contents

Sometimes we'll want to change permissions for an entire directory. That is, the directory itself, and every file and subdirectory it might contain.

Here's an example. We have a directory called projects.

drwxrwxr-x 4 alex alex   4096 Mar 24 21:38 projects

Inside this directory we have two subdirectories (project1 and project2) and two files (file1 and file2):

Note that at this point other users do not have the w write permissions. But let's just say that we want to allow others to write to all of these objects:

  • The projects directory itself. And all of its contents:
    • The files it contains.
    • The subdirectories it contains.
    • And everything else that might be on deeper levels (sub-subdirectories, files those might contain, and so on).

To do this, we can tell chmod to change permissions recursively. All we need to do is add the -R recursive option to the command.

💡
Note that it's an uppercase R. A lowercase r has a different meaning.

The command we can use to to recursively add the write permission for others, on the projects directory, is:

chmod -R o+w projects

Note how the w permission now appears in every file and subdirectory, in the others permission set. w is also enabled on the parent directory itself, projects.

With one command we changed permissions on the parent directory, the files inside, and the subdirectories inside. That's the power of the -R recursive option for chmod.

But the recursive option here also brings a potential problem.

Note how file1 and file2 have the x executable permission disabled. Which makes sense. Maybe those are regular text files. So there's no reason to make them executable.

Now imagine this. For simplicity, let's say the files and subdirectories inside the projects subdirectory have no permissions enabled:

And let's say we want to add a simple set of permissions:

  • For the files: The user that owns them should be able to read and write. No execute, since these are text files that do not require the x permission.
  • For the directories: The user that owns them should be able to read, write, and execute. Because without an x on directories, users wouldn't be able to "step inside" those directories, and browse them.

Note the problem. We need:

  • rw for files.
  • rwx for directories.

If we'd recursively add rwx to the projects directory, then files would receive an x they do not need.

If we'd recursively add just rw to the projects directory, then directories would not receive the x they actually need.

Luckily, chmod has us covered! With a very simple trick we can tell chmod:

  • If it's a directory then add / set the executable permission.
  • If it's a file then DO NOT add / set the executable permission.

All we have to do is use an uppercase X instead of the lowercase x.

So, for the projects directory, here's how we recursively:

  • Add rw to files.
  • And rwx to directories.

For the user set of permissions, with a single command:

chmod -R u+rwX projects

Before, things looked like this:

But after our last command they look like this:

Exactly as expected. rw added for files, and rwx added for directories. With a simple uppercase X we told chmod to intelligently add x only for directories.

It's worth mentioning that there's an exception to this rule, where capital X tells chmod to only add / set x permission if the object is a directory. chmod will also check if the file already has the x executable permission set somewhere. For example, for a file that has these permissions:

rw-rw-r--

A chmod command with o+X won't add the executable permission in the others field.

But if the file has these permissions:

rwxrw-r--

A chmod command with o+X WILL add the executable permission in the others field. That's because although this is a file, and not a directory, it already has x in the user set of permissions. Since it's already executable for the user, the chmod command assumes we also want to add executable permission for others.

Although an exception to "only add x if it's a directory" rule, it makes sense. If this is a file, and we don't have x anywhere, we probably don't want it to be executable at all. But if it already has x somewhere, then we probably want to make it executable for someone else too (user owner, group owner, or others).

Change SUID, SGID and Sticky Bit Permissions with chmod

We discussed the effects of SUID, SGID, and sticky bit in-depth in this blog explaining how file and directory permissions work on Linux.

SUID and SGID on Files

What's important to remember is that if we intend to enable SUID on a file, we should first change the owner of that file. If we do it in reverse order (SUID first, then change the owner) as soon as the owner is changed, the SUID permission is lost.

So: Owner first, SUID second.

That's if we want this file to be executed as someone else rather than the current owner. If the current owner is what we want, then we can skip the first step (the chown command) and jump directly to adding SUID with chmod.

Here's an example.

First we change the owner of this file to a user called john:

sudo chown john executable_file

chown john changes the owner to a user called john. And executable_file is the name of the file.

sudo is needed to run this command with administrative privileges. Since only the administrative user, root can change the owner of a file (or directory).

The effect:

The first field here shows the user that owns the file. Which is now john.

The second field shows the group that owns the file. Which is currently alex, but this is irrelevant at this point. Only the user owner is important for SUID.

Finally, we can use chmod to enable the SUID permission on this file. We'll also need administrative privileges for this, so we'll add sudo in front of our chmod command:

sudo chmod u+sx executable_file

And note that instead of rwx in the first set, for user permissions, we see rws. That s signals that: SUID permission is enabled, and the file is executable. If SUID would be enabled, but the file would not be executable, we'd see an uppercase S instead of a lowercase s).

Normally, we could have just ran sudo chmod u+s executable_file instead of sudo chmod u+sx for.sh.

But we used sx instead of a simple x for this reason: To ensure that the file is also executable. Because SUID s permission without x is useless. Both s and x need to be active, so it's a good habit to enable both when we need SUID.

If we need to remove SUID, we can do that with a simple command like:

sudo chmod u-s executable_file

For SGID the approach is similar. But instead of the user that owns that file, we change the group that owns that file. Let's change it to a group called john:

sudo chgrp john executable_file

We can see the group that owns the file in the second field here.

Next, we add / enable the SGID bit / permission with:

sudo chmod g+sx executable_file

An s letter in this spot tells us that SGID and executable permissions are both enabled for the group owner of this file.

To remove SGID, we could run a command like this:

sudo chmod g-s executable_file

On Linux, only SUID and SGID have an effect on files. The sticky bit has no effect on files, just on directories.

SGID and Sticky Bit on Directories

On most Linux systems, SUID has no effect on directories. Only SGID and sticky bit have effects on directories.

If you want to learn more about SGID, and sticky bit on directories, you can read this guide about how file and directory permissions work on Linux.

Before we add SGID on a directory, we need to decide: What group do we want to automatically become the owner of files / subdirectories created inside this directory?

For example, to change the group owner to www-data, for a directory called web_project, we'd run this command:

sudo chgrp www-data web_project

Now the directory looks like this:

drwxrwxr-x 2 alex www-data   4096 Mar 25 23:56 web_project

To enable / add SGID on the web_project directory, we can run this command:

sudo chmod g+s web_project

The result:

drwxrwsr-x 2 alex www-data   4096 Mar 25 23:56 web_project

We see a rws in the group-level permissions. Where the last lowercase s signals that SGID is active, and the directory is executable by the group that owns it.

💡
Note: If we later change permissions on that directory, SGID might get disabled. So remember to re-check after every permission change if SGID is still on. If it isn't, simply re-enable it with a chmod g+s command.

To remove SGID from a directory, we can run a command like this:

sudo chmod g-s web_project

Finally, the sticky bit. To add the sticky bit on our web_project directory, we can run this command:

chmod o+t web_project

Or:

sudo chmod o+t web_project

If our user does not own this directory.

The last lowercase t in here signals that the directory has the sticky bit enabled (and that it's executable by other users).

To remove the sticky bit:

chmod o-t web_project

# Or, if we don't own the directory:

sudo chmod o-t web_project

And that covers every important use case of the chmod command.