One of the most common errors in Linux, familiar to virtually every administrator, is the Permission denied error. Generally speaking, it means that a user or a running process is attempting to perform an operation for which it lacks sufficient access rights. For example, a web server might be unable to read a configuration file, a PHP application might refuse to save uploaded images, or your Bash script might fail to run even though the file itself exists and is in the correct location.
There can be various reasons for this error, but most often such problems arise after migrating a website to a new VPS, restoring a backup, or, for example, changing web server settings.
The simplest solution to this problem, which is often suggested on forums, is to run the command chmod 777 {file_name}. Sure, the error may indeed disappear after that, but along with it, access restrictions for other system users will also disappear. On a production server where important files and data are stored, this approach can create huge security issues. Therefore, NEVER do this until you’ve verified that such permissions are actually necessary for this specific file (which is highly unlikely).
Fortunately, Linux offers several simple tools for managing file and directory permissions that allow you to determine who owns a particular file, what operations can be performed on it, and why the system is denying access to the file.
In this brief article, we’ll look at the main commands for checking access permissions and ways to fix the most common errors related to access permissions.
How Access Permissions Work in Linux
The access permission system in Linux was inherited from Unix, where a similar mechanism first appeared back in the 1970s. Even then, Unix was being developed as a multi-user operating system in which several people could work simultaneously on a single computer. To prevent users from arbitrarily reading, modifying, or deleting other users’ files, a mechanism for restricting access was needed.
Linux has retained this model virtually unchanged, as it is both very simple and elegant. Despite its age, it is still used on servers, workstations, and other devices running various Linux distributions.
The essence of the method is quite simple. Every file and directory has an owner, a group, and a set of permissions. When attempting to open or modify a file, the Linux kernel checks which user is performing the operation and what actions they are permitted to perform.
Three categories are used for this purpose:
- Owner (u) - the file’s owner;
- Group (g) - users in the group to which the file belongs;
- Others (o) - all other users on the system.
For each category, the following permissions are defined: r (read), w (write), and x (execute). These can also be combined. For example, the owner can read and modify the file, group members can only read it, and everyone else has no access to it at all.
However, there is a nuance when working with directories. The r permission allows viewing the list of filenames, x allows accessing objects within the directory by their known names, and w allows modifying its contents. In other words, creating and deleting files usually requires both w and x permissions.
Therefore, there are often cases where even a file with read permission may be inaccessible because the user lacks permission to traverse one of the parent directories.
This system is simple enough for day-to-day administration, although it does have its limitations. For more flexible access control in Linux systems, additional mechanisms are used, such as ACLs (Access Control Lists), which allow you to assign specific permissions to particular users and groups.
Now that we’ve covered the basics, let’s move on to the practical part.
Checking Permissions with the `ls -l` Command
The easiest way to view the permissions of a specific file is to run the following command:
ls -l /var/www/html/index.php
Example output:
-rw-r--r-- 1 www-data www-data 2450 Oct 20 12:30 index.php
The sequence -rw-r--r-- indicates the file type and its permissions. The first character - denotes a regular file (d denotes a directory). The remaining characters are divided into groups of three.
In this example, the owner www-data can read and modify the file, while the group and other users can only read it.
To check the directory itself, use the command:
ls -ld /var/www/html
The -d option is needed to get information about the directory itself, rather than its contents.
How to view permissions in numeric format
In Linux, permissions are often written as numbers: 644, 755, 600. Each action corresponds to a value:
r = 4- read.w = 2- write.x = 1- execute.
The numbers are calculated separately for each user category.
For example, 755 means full access for the owner (7 = 4 + 2 + 1) and read and execute permissions for others (5 = 4 + 1).
You can check numeric permissions using the stat command:
stat -c '%a %n' /var/www/html/index.php
Result:
644 /var/www/html/index.php
The most commonly used combinations are as follows:
|
Permissions |
Typical Use |
|---|---|
|
|
Regular website files |
|
|
Directories and executable files |
|
|
Private keys and files accessible only to their owner |
|
|
Private user directories |
|
|
Website configuration files containing passwords (e.g., .env or wp-config.php) |
We’ve listed only the most common options here, but specific permissions depend on your application’s requirements or your server’s security policies.
How to Check the File Owner
Sometimes an access permissions error can occur due to an incorrect file or directory owner. This often happens after migrating a website between servers or restoring website files from a backup.
You can find the owner and group using the command:
stat -c '%U %G' /var/www/html/config.php
For example:
root www-data
Here, the owner is root, and the group is www-data.
If the application runs as www-data, you need to check whether this user can read the file:
sudo -u www-data test -r /var/www/html/config.php && echo "Reading permitted"
If the message does not appear, the check failed to confirm access.
Note that the test -r command checks only the permissions of the file itself. If the message does not appear, the problem may not be with the file itself, but - for example - with the lack of x execution permissions for the www-data user on one of the parent directories.
Similarly, you can check write permissions by replacing the -r option in the command with the -w option.
Why Is the File Accessible, but a "Permission Denied" Error Occurs?
Suppose the file has permissions 644, but the application still cannot open it. The reason for this behavior may lie in the parent directory. In this case, it’s helpful to check the entire directory chain along the path to the target file. This is done with the command:
namei -l /srv/project/data/report.txt
It will display the permissions for each element in the path, and if the user running this command lacks the x execution permissionon even one of the parent directories, access to the file will be blocked.
There are also less obvious causes. For example, additional ACL rules or SELinux and AppArmor restrictions.
You can spot them directly in the output of the ls -l command. For instance, if ACL rules are set on a file, a plus sign appears at the end of the permissions list (for example, -rw-r-----+), and when SELinux is enabled, a period appears (for example, -rw-r--r--.).
You can check the ACL rules using the following command:
getfacl /var/www/html/config.php
And if the file does not run even with the correct permissions, then you need to check the mount options:
findmnt -T /var/www/html/script.sh -o TARGET,OPTIONS
Example output for a filesystem mounted with the noexec option:
TARGET OPTIONS /var/www rw,nosuid,nodev,noexec,relatime
Here, rw means that the filesystem is accessible for reading and writing, while noexec prevents executable files from being run directly from this partition.
If the file system is mounted in "read-only" mode, the output might look like this:
TARGET OPTIONS /var/www ro,relatime
And for a standard mount without these restrictions, the output should be as follows:
TARGET OPTIONS /var/www rw,relatime
Of course, these are hypothetical examples, and the actual parameters depend on your server’s configuration. But we think you get the idea.
How to Change Access Permissions
To change permissions on files and directories, use the chmod command (short for “Change Mode”):
chmod 640 /var/www/html/config.php
Now the owner can read and modify the file, the group can only read it, and all other users have no access to this file.
If the problem is related to the owner, then use the chown command (short for Change Owner):
sudo chown www-data:www-data /var/www/html/config.php
Note that you should only set the owner to the www-data user when your application truly requires it - for example, if the web server or a PHP process needs to create and modify files in a specific directory. For regular website files that only need to be read, such a change of ownership is usually unnecessary. Furthermore, if all files belong to the www-data user, a vulnerability in the web application could allow an attacker to modify your website’s source code or configuration. Therefore, it’s best to grant write permissions only to those directories and files where they are truly necessary.
After migrating a website, you sometimes have to correct permissions for a large number of objects at once. For directories and regular files, it’s best to set them individually:
find /var/www/html -type d -exec chmod 755 {} +
find /var/www/html -type f -exec chmod 644 {} +
This is a typical scheme for public website files, but applying it to the entire project without verification is dangerous. Private configurations may require stricter permissions, and executable files, for example, may require execute permissions.
IMPORTANT! Let’s reiterate that it is particularly inadvisable to use chmod -R 777, as this command grants write and execute permissions to all system users, which creates unnecessary risks.
In summary, to resolve most access permission issues in Linux, it is sufficient to know the commands ls -l, stat, and namei. These commands allow you to quickly check permissions, the file owner, and the availability of parent directories. However, you should never neglect the security of your server. Therefore, it’s important to approach permissions management wisely by planning your actions in advance and verifying exactly which permissions you’re granting and to whom.