File permissions are one of those Linux topics that look simple until something breaks. A script will not run, a web server cannot read a file, a backup misses data, or a cleanup job starts failing because the user running it does not have access. When that happens, permissions stop being theory and become the thing standing between you and a working system. I have dealt with that enough times that I pay attention to permissions early instead of treating them as an afterthought.
Permissions are also part of security. A file that is readable by everyone might expose information that should stay private. A directory that is writable by the wrong user can become a place where bad files get dropped. On a server, small permission mistakes can turn into bigger problems because web servers, cron jobs, scripts, and real users all touch the same filesystem in different ways.
I do not think permissions need to be intimidating. The main idea is deciding who can read, write, or execute a file. Once that clicks, commands like chmod, chown, and ls -l start making a lot more sense. The trick is learning how to read what Linux is already telling you.
Reading The Permission String
The first place I usually look is the long listing output from ls. That output shows the file type, permissions, owner, group, size, date, and name. It looks dense at first, but the permission string is very structured. Once you know how to break it apart, it becomes one of the fastest ways to understand what is happening.
I usually start with one file so the output is easy to read. That keeps the example focused on the permission string instead of a long directory listing. Here is a simple command to inspect one script.
ls -l backup.sh
The output gives me the permissions first, then the owner and group. After that, it shows the size, date, and filename. The important part for this section is the first field.
-rwxr-xr-- 1 jmoorewv staff 842 Jul 16 09:30 backup.sh
I like to separate that first field visually before thinking about the rest of the line. The first character tells me the file type, and the next nine characters are the permission groups. This diagram shows how I read that first field.
- rwx r-x r-- | | | | | | | +-- others | | +------ group | +---------- owner +------------ file type
The first character tells me what kind of filesystem object I am looking at. A regular file starts with -, while a directory starts with d. After that, the next nine characters are split into three groups. Those groups describe permissions for the owner, the group, and everyone else.
In that example, the owner has rwx, the group has r-x, and everyone else has r--. That means the owner can read, write, and execute the file. Members of the group can read and execute it, but they cannot change it. Everyone else can only read it.
Owner, Group, And Everyone Else
Linux permissions are built around three permission targets. The owner is usually the user who created the file or the user who has been assigned ownership. The group is a collection of users that can share access. Everyone else means any user who is not the owner and is not part of the assigned group.
This split matters on servers because different processes often run as different users. A web server might run as www-data, a deployment script might run as a specific account, and a backup job might run as root or a backup user. If ownership is wrong, the command itself might be fine while the filesystem refuses to cooperate. That is why permission problems often feel confusing at first.
You can see the owner and group in the same ls -l output. In this example, jmoorewv is the owner and staff is the group. The permission string only makes sense when you read it together with those names. A file can have perfect looking permission bits and still fail if the wrong user owns it.
Another way to picture it is to separate identity from access. The permission string says what the owner, group, and everyone else can do. The owner and group fields tell me who those first two permission groups actually refer to.
-rwxr-xr-- 1 jmoorewv staff 842 Jul 16 09:30 backup.sh
| |
| +-- group name
+----------- owner nameWhat Read, Write, And Execute Mean
The letters are easy to remember, but their meaning changes depending on whether you are looking at a file or a directory. For a file, read means the contents can be viewed. Write means the contents can be changed. Execute means the file can be run as a program or script.
Directories behave differently. Read lets a user list the names inside the directory. Write lets a user create, delete, or rename entries in that directory. Execute lets a user enter the directory and access items inside of it if they already know the path.
That directory execute bit surprises people. A directory can have read permission without execute permission, but it will still be awkward or useless in normal work. On the other side, a directory can have execute permission without read permission, which allows access to known paths without allowing a full directory listing. That distinction shows up in web hosting, shared folders, and locked down service directories.
A common pattern is that directories need execute permission when users or services need to pass through them. Files only need execute permission when they are meant to run. Giving execute permission to every file is usually a sign that someone used a broad command without thinking through the difference.
Understanding Numeric Permissions
Numeric permissions are just a shorthand for read, write, and execute. Read is worth four, write is worth two, and execute is worth one. Add them together for each permission target. That gives you the three digit values people use with chmod.
The numbers become easier once you stop treating them like codes to memorize. Each value is just a total for one permission group. These are the common values I use when reading or setting modes.
7 = read + write + execute 6 = read + write 5 = read + execute 4 = read only 0 = no access
The numeric form is just the same three groups compressed into digits. I read the first digit as owner, the second as group, and the third as everyone else. This makes a value like 754 easier to reason through.
7 5 4 | | | | | +-- others: 4 = read | +---- group: 5 = read + execute +------ owner: 7 = read + write + execute
When you see 755, read it as owner, group, and everyone else. The owner gets seven, which means read, write, and execute. The group gets five, which means read and execute. Everyone else gets five too.
When you see 644, the owner can read and write, while the group and everyone else can read. That is common for regular website files, configuration examples, and documents that should not be executable. It is not a magic number, but it is a useful pattern when the file only needs to be read by other users or services.
I try not to memorize permissions as random numbers. I prefer to translate them back into what they allow. That habit helps prevent mistakes like setting everything to 777 just to make an error go away.
Changing Permissions With chmod
The chmod command changes permission bits. You can use numeric mode when you already know the full permission set you want. You can also use symbolic mode when you only want to add or remove one part. I use both, depending on whether I am setting a known baseline or making a small adjustment.
Numeric mode is direct when I want to set the full permission pattern. I use it when I already know what the file should look like afterward. These examples show a few common choices.
chmod 644 notes.txt chmod 755 deploy.sh chmod 700 private-script.sh
The first command makes a regular file readable by others but writable only by the owner. The second command makes a script executable while still allowing others to read and run it. The third command locks a script down so only the owner can read, write, and execute it. Those are different choices for different jobs.
Symbolic mode is useful when I want to make a focused change. For example, I can add execute permission for the owner without replacing the whole permission set. That is safer than typing a numeric value from memory when I only need to change one bit.
chmod u+x deploy.sh chmod g-w shared-notes.txt chmod o-r private.txt
In symbolic mode, u means user, g means group, and o means others. The plus sign adds a permission, and the minus sign removes one. This reads more like a sentence, which can make it easier to review in a command history later.
Changing Ownership With chown And chgrp
Permissions only tell part of the story. Ownership decides which user and group those permission bits apply to. If a file is owned by the wrong user, changing the permission number may only hide the real problem. I usually check ownership before I start changing modes.
The chown command changes the owner, and it can also change the group at the same time. The chgrp command changes only the group. On most systems, changing ownership requires elevated privileges because it affects access control. That is why these commands often appear with sudo.
Ownership commands are short, but they can affect how every permission check behaves. I like to keep the examples simple before applying them to larger directory trees. These commands show the basic forms.
sudo chown jmoorewv report.txt sudo chown jmoorewv:staff report.txt sudo chgrp www-data uploads
The first command changes the file owner. The second changes both the owner and the group. The third leaves the owner alone and changes only the group. When I am fixing web directory access, that group assignment is often the part that matters most.
I am careful with recursive ownership changes. A command like chown -R can fix a directory tree quickly, but it can also break a system quickly if the path is wrong. I always double check the target path before running recursive ownership changes, especially under web roots, home directories, or application folders.
Using Recursive Changes Carefully
Recursive permission changes are where a lot of damage happens. The command itself is not dangerous when used carefully, but it applies the change to everything under the target path. That can include files, directories, scripts, uploads, cache folders, and configuration files. Those things often should not all have the same permissions.
This is the kind of command I avoid unless I know exactly what is under the directory. It is often used as a quick fix when an application cannot write somewhere. The problem is that it fixes access by removing almost all restraint.
chmod -R 777 /var/www/html
That command gives everyone read, write, and execute permission across the entire tree. It may make an error disappear, but it usually creates a worse security problem. On a web server, world writable files and directories are rarely the right answer. If a process needs write access, I would rather fix the owner or group than open the door for everyone.
When I need to correct a mixed directory tree, I usually separate files and directories. Directories often need execute permission so users and services can pass through them. Regular files usually do not need execute permission unless they are scripts or binaries. The find command helps apply different modes to each type.
find /var/www/example -type d -exec chmod 755 {} \;
find /var/www/example -type f -exec chmod 644 {} \;Those commands are still powerful, so the path matters. I like to run the matching find command without -exec first if I am unsure what it will touch. Seeing the list before changing anything has saved me from more than one bad command.
Understanding umask
Permissions are not only changed after files are created. Linux also uses a value called umask to decide the default permissions for new files and directories. The easiest way to think about it is that umask removes permissions from the default starting point. It helps keep newly created files from being too open.
The current value is easy to check from a shell. I like knowing it when a script creates files with permissions I did not expect. This command shows the active value for the current shell.
umask
A common value is 022. That usually results in new files being created as 644 and new directories as 755. The exact effect depends on whether the new item is a file or directory because regular files do not normally start with execute permission.
I pay attention to umask when scripts create files that other users or services need to read. A backup script, deployment script, or generated report can fail later if the defaults are too restrictive or too open. The right value depends on the environment, but it should be intentional.
Special Permission Bits
Most day to day permission work uses read, write, and execute, but Linux has special bits too. The ones I run into most are setuid, setgid, and the sticky bit. These are not settings I change casually, but they are worth recognizing when they appear in permission strings. They explain some behavior that normal permission bits do not cover.
The special bits show up inside the same owner, group, and others positions that normally hold execute permission. Setuid appears in the owner execute position. Setgid appears in the group execute position. The sticky bit appears in the others execute position.
Lowercase and uppercase matter here. A lowercase s or t means the special bit is set and execute permission is also set for that position. An uppercase S or T means the special bit is set, but execute permission is not set. That usually deserves a closer look because the special bit may not behave the way someone expected.
The easiest way to recognize these bits is to look at where the letter appears. The owner, group, and others positions do not move. Only the execute character changes when a special bit is present.
owner group others
r w x r w x r w x
| | |
| | +-- sticky bit replaces others execute with t or T
| +----------------- setgid replaces group execute with s or S
+-------------------------------- setuid replaces owner execute with s or S-rwsr-xr-x setuid with owner execute -rwSr-xr-x setuid without owner execute drwxrwsr-x setgid with group execute drwxrwSr-x setgid without group execute drwxrwxrwt sticky bit with others execute drwxrwxrwT sticky bit without others execute
Setuid is most often seen on executable files where the program needs to run with the file owner’s privileges. Setgid can appear on executable files too, but I often care about it on directories because new files can inherit the directory’s group. That can be useful in shared project folders where group ownership needs to stay consistent.
The sticky bit is common on shared temporary directories. It allows multiple users to write inside a directory while preventing them from deleting each other’s files. That is why /tmp usually has permissions that look different from a normal directory.
ls -ld /tmp
drwxrwxrwt 10 root root 4096 Jul 16 10:15 /tmp
The t at the end is the sticky bit. If that last character were uppercase T, the sticky bit would still be set, but others would not have execute permission on the directory. That difference is easy to miss in a long listing. If I see setuid, setgid, or sticky bits somewhere unexpected, I stop and look closer before changing anything.
A Practical Web Directory Example
Web directories are where permission mistakes show up constantly. A web server needs to read files, sometimes write uploads or cache files, and usually should not be able to modify everything. The exact user and group depend on the distribution and server setup. On many Debian and Ubuntu systems, Apache runs as www-data.
A simple starting point should separate ownership from permission modes. The user who manages the files and the group used by the web server both matter. This example shows one common pattern.
sudo chown -R jmoorewv:www-data /var/www/example
find /var/www/example -type d -exec chmod 755 {} \;
find /var/www/example -type f -exec chmod 644 {} \;That gives ownership to the user who manages the files and assigns the web server group. Directories are readable and searchable, while regular files are readable without being executable. This is not a universal rule, but it is a safer starting point than making everything writable. Any directory that truly needs web server write access should be handled deliberately.
Uploads are different because the application may need to create files. I still prefer to make that change only where it is needed. For an uploads directory, I might adjust the group write permission like this.
sudo chmod 775 /var/www/example/uploads
That kind of change should be narrow. I would rather grant write access to one directory that needs it than loosen permissions across the whole site. If a web application needs more than that, I want to understand why before I change anything else.
Common Permission Mistakes
The most common mistake is using 777 as a shortcut. It can make an error disappear, but it gives every user read, write, and execute access. That is rarely the real fix. It usually means ownership, group membership, or a specific directory permission needs to be corrected instead.
Another mistake is forgetting that directories need execute permission. A file can have readable permissions, but if a user cannot pass through the parent directories, access still fails. This is one reason permission errors can feel misleading. The file itself may look fine while the path leading to it is blocked.
Recursive changes are another easy place to cause trouble. Applying the same mode to every file and directory ignores the fact that files and directories need different things. It can also make scripts executable when they should not be, or make configuration files more exposed than necessary. I try to use recursive commands only when I understand the entire tree.
The last mistake is changing permissions before checking ownership. If a service cannot write to a directory because the wrong user owns it, opening the permissions wider only treats the symptom. The better fix is usually assigning the right owner or group. That keeps access limited to the users and processes that actually need it.
How I Think About Permissions
When I troubleshoot permissions, I start by asking which user is trying to do the work. Then I check the file, the owner, the group, and every parent directory in the path. That usually tells me where access is being blocked. Guessing with chmod is faster for a few seconds, but it can create problems that take much longer to clean up.
I also think in terms of the least access needed. If a file only needs to be read, it should not be writable. If a directory only needs uploads, the whole application tree does not need write access. If one service account needs access, everyone else probably does not.
Linux permissions are not just a command line detail. They are part of how the system explains who is allowed to do what. Once you get comfortable reading that information, permission problems become much less mysterious. You stop guessing and start following the evidence.





















