Runtimes Intermediate

Troubleshooting PHP-FPM Socket Permission Denied: Nginx User/Group Mismatch on Alpine Linux

Resolve 'PHP-FPM socket permission denied' errors on Alpine Linux caused by Nginx and PHP-FPM user/group mismatches. Fix your 502 Bad Gateway now!

👨‍💻
Senior Systems Architect • Verified in Staging Labs

Resolve 'PHP-FPM socket permission denied' errors on Alpine Linux caused by Nginx and PHP-FPM user/group mismatches. Fix your 502 Bad Gateway now!

When deploying web applications on Alpine Linux using Nginx and PHP-FPM, encountering a "PHP-FPM socket permission denied" error is a common hurdle. This issue typically manifests as a 502 Bad Gateway error in the browser and indicates that Nginx, acting as the web server, lacks the necessary permissions to communicate with the PHP-FPM service via its Unix socket. This guide will walk you through diagnosing and resolving this user/group mismatch.

Symptom & Error Signature

The most direct symptom you'll encounter is a 502 Bad Gateway error displayed in your web browser when trying to access PHP pages. On the server, the definitive error signature will be found in your Nginx error logs, typically located at /var/log/nginx/error.log.

Nginx Error Log Example:

2026/09/27 10:30:45 [crit] 1234#1234: *1 connect() to unix:/var/run/php-fpm/php-fpm.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.1.100, server: example.com, request: "GET /index.php HTTP/1.1", upstream: "fastcgi://unix:/var/run/php-fpm/php-fpm.sock:", host: "example.com"

You might also see a similar error if you try to curl your application locally:

$ curl -I http://localhost/index.php
HTTP/1.1 502 Bad Gateway
Server: nginx/1.24.0
Date: Mon, 27 Sep 2026 10:30:45 GMT
Content-Type: text/html
Content-Length: 172
Connection: keep-alive

Root Cause Analysis

The "Permission denied" error indicates a fundamental access control problem. On Unix-like systems, processes run under specific user and group identities, and access to files, directories, and IPC mechanisms (like Unix domain sockets) is governed by these identities.

The root cause of this particular error is almost always a mismatch in the user and group permissions between the Nginx process and the PHP-FPM process (or more precisely, the permissions of the Unix socket created by PHP-FPM).

Here's a breakdown of the common contributing factors:

  1. Default User/Group Mismatch:

    • Nginx: On Alpine Linux (and many other distributions), Nginx typically runs as the nginx user and nginx group.
    • PHP-FPM: PHP-FPM, by default, often runs as the php-fpm user and php-fpm group, or sometimes nobody or www-data (though php-fpm is standard on Alpine for its daemon).
    • When PHP-FPM creates its Unix socket (e.g., /var/run/php-fpm/php-fpm.sock), it assigns ownership and permissions based on its configured user and group. If the Nginx user (nginx) is not part of the PHP-FPM's group (php-fpm) and the socket's permissions are restrictive (e.g., 0660), Nginx will be denied access.
  2. Incorrect php-fpm Pool Configuration (www.conf):

    • The listen.owner, listen.group, and listen.mode directives within the PHP-FPM pool configuration (/etc/phpX/php-fpm.d/www.conf on Alpine) directly control the ownership and permissions of the Unix socket. If these are not configured to allow the Nginx user access, the error will occur.
  3. Parent Directory Permissions:

    • Less common for the socket itself, but sometimes the parent directory (/var/run/php-fpm/ in this case) might have incorrect permissions, preventing PHP-FPM from even creating the socket with the desired permissions, or preventing Nginx from traversing the directory.
  4. SELinux/AppArmor (Less likely on Alpine):

    • While not standard on a default Alpine installation, if you're running a custom kernel or a more complex security setup, mandatory access control systems like SELinux or AppArmor could also enforce restrictions. However, for Alpine, the vast majority of "permission denied" issues are standard Unix discretionary access control problems.

Step-by-Step Resolution

The goal is to ensure that the Nginx user has read/write access to the PHP-FPM Unix socket. We'll achieve this by modifying the PHP-FPM pool configuration.

1. Identify Running Users and Configuration Paths

First, let's confirm the users under which Nginx and PHP-FPM are running, and locate their configuration files.

# Check Nginx user (usually 'nginx')
ps aux | grep -E '[n]ginx' | head -n 1 | awk '{print $1}'

# Check PHP-FPM user (e.g., 'php-fpm' or 'nobody')
ps aux | grep -E '[p]hp-fpm' | head -n 1 | awk '{print $1}'

# Locate PHP-FPM www.conf (replace 'X' with your PHP version, e.g., php81)
find /etc/php* -name www.conf

# Locate Nginx configuration file
find /etc/nginx -name nginx.conf

On Alpine Linux, PHP versions are typically installed in separate directories, e.g., /etc/php81/php-fpm.d/www.conf for PHP 8.1. Adjust commands accordingly.

2. Inspect Nginx Configuration for Socket Path

Confirm that Nginx is configured to use the correct Unix socket path. Open your Nginx site configuration (e.g., /etc/nginx/conf.d/default.conf or your specific virtual host file) and look for the fastcgi_pass directive.

# Example Nginx site configuration
server {
    listen 80;
    server_name example.com;
    root /var/www/html;
    index index.php index.html;

    location ~ .php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+.php)(/.+)$;
        fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; # <--- This is the socket path
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

Verify the fastcgi_pass directive points to the correct socket path. If it's different from /var/run/php-fpm/php-fpm.sock, make a note of it.

3. Modify PHP-FPM Pool Configuration (www.conf)

This is the core fix. We will adjust the php-fpm pool configuration to allow the Nginx user access to the socket.

Open the www.conf file for your PHP-FPM version (e.g., /etc/php81/php-fpm.d/www.conf).

# Example for PHP 8.1
apk add nano # if you don't have a text editor
nano /etc/php81/php-fpm.d/www.conf

Locate the listen directive and the listen.owner, listen.group, and listen.mode directives. They usually look something like this:

; php-fpm.d/www.conf (default on Alpine)
listen = /var/run/php-fpm/php-fpm.sock
listen.owner = php-fpm
listen.group = php-fpm
listen.mode = 0660

Here are the recommended solutions:

Option A: Add Nginx User to PHP-FPM Group (Recommended for Separation)

This is generally the most secure and recommended approach as it maintains separation of concerns. PHP-FPM still runs as its own user, but Nginx is granted access via group permissions.

  1. Ensure listen.owner and listen.group are set correctly:

    • listen.owner: Should be the user PHP-FPM is running as (e.g., php-fpm).
    • listen.group: Should be the group PHP-FPM is running as (e.g., php-fpm).
    • listen.mode: Crucially, set this to 0660 to allow read/write access for the owner and group.
    ; In /etc/phpX/php-fpm.d/www.conf
    listen = /var/run/php-fpm/php-fpm.sock
    listen.owner = php-fpm
    listen.group = php-fpm
    listen.mode = 0660
    
  2. Add the Nginx user to the PHP-FPM group:

    • Find the actual group name PHP-FPM uses (e.g., php-fpm).
    • Find the actual user name Nginx uses (e.g., nginx).
    # Add 'nginx' user to 'php-fpm' group
    # Note: 'adduser' is for adding new users. 'addgroup' is for adding existing users to a group.
    # On Alpine, 'addgroup' is usually used like this:
    addgroup nginx php-fpm
    

    If the php-fpm group doesn't exist, it might be that PHP-FPM runs as nobody or www-data. Adjust listen.group to the correct group (e.g., www-data) and then add nginx to that group. However, on Alpine, a dedicated php-fpm user and group are standard.

Option B: Change PHP-FPM Socket Ownership to Nginx User/Group (Simpler, Less Secure)

This approach is simpler but ties the PHP-FPM socket directly to the Nginx user, which might be less ideal for strict permission separation.

  1. Modify www.conf to set listen.owner and listen.group to nginx:

    ; In /etc/phpX/php-fpm.d/www.conf
    listen = /var/run/php-fpm/php-fpm.sock
    listen.owner = nginx
    listen.group = nginx
    listen.mode = 0660
    

    While simpler, this means the PHP-FPM process (which typically runs as php-fpm or nobody) will need elevated privileges to create the socket as nginx if it's not already running as nginx. Ensure the user and group directives within www.conf also match nginx if you choose this option:

    user = nginx
    group = nginx
    

    This would mean PHP-FPM processes run as nginx, which grants them the same permissions as Nginx itself, potentially reducing security if the PHP application is compromised. Option A is generally preferred.

4. Verify Socket Directory Permissions (If Necessary)

Ensure the directory where the socket is created (/var/run/php-fpm/) has appropriate permissions. PHP-FPM should be able to create the socket there.

# Check permissions for the directory
ls -ld /var/run/php-fpm/

# Example output
# drwxr-xr-x    2 php-fpm  php-fpm       60 Sep 27 10:45 /var/run/php-fpm/

# If the directory doesn't exist or has wrong permissions for php-fpm,
# you might need to create it and set permissions.
# This is usually handled by the php-fpm package, but can be useful for debugging.
# Example:
# mkdir -p /var/run/php-fpm/
# chown php-fpm:php-fpm /var/run/php-fpm/
# chmod 755 /var/run/php-fpm/

The php-fpm user/group needs write access to this directory to create the socket. drwxr-xr-x owned by php-fpm:php-fpm is usually sufficient.

5. Restart Services

After making changes to www.conf or user groups, you must restart both PHP-FPM and Nginx for the changes to take effect.

# Restart PHP-FPM
rc-service php-fpm restart

# Restart Nginx
rc-service nginx restart

On Alpine, rc-service is the standard way to manage services. If you're running in a Docker container and process management is handled differently, you might need to stop/start the container or directly restart processes.

6. Verify the Fix

  1. Check PHP-FPM socket permissions: After restarting PHP-FPM, verify the ownership and permissions of the created socket.

    ls -l /var/run/php-fpm/php-fpm.sock
    

    Expected output for Option A:

    srw-rw---- 1 php-fpm php-fpm 0 Sep 27 10:50 /var/run/php-fpm/php-fpm.sock
    

    This shows the socket owned by php-fpm:php-fpm with 0660 permissions. Since the nginx user is now part of the php-fpm group, Nginx will have read/write access.

    Expected output for Option B (if you also changed user=nginx in www.conf):

    srw-rw---- 1 nginx nginx 0 Sep 27 10:50 /var/run/php-fpm/php-fpm.sock
    
  2. Test your website: Open your browser and navigate to your website. PHP pages should now load correctly without the 502 Bad Gateway error.

  3. Check Nginx error logs: Confirm that no new Permission denied errors appear in /var/log/nginx/error.log.

By following these steps, you should successfully resolve the "PHP-FPM socket permission denied" error on your Alpine Linux system. Remember to prioritize Option A for better security and process separation.

👨‍💻

Johnathon Wheeler

Senior Systems Architect & DevOps Engineer • Austin, TX

Connect on LinkedIn →

Johnathon has over 16 years of hands-on experience designing, debugging, and scaling Linux web hosting stacks, container clusters, and high-availability database architectures. Every guide on ButItWorkedLocal is independently tested against Debian 12, Ubuntu 24.04/22.04 LTS, Rocky Linux, and Docker environments to guarantee reproducibility in production.

🛡️

Our Production Verification Guarantee

Encountering a bug not covered here or running a non-standard kernel configuration? Our solutions are continually refined against real production incidents. Submit an environment trace for our editorial team to replicate.