PHP sessions are crucial for maintaining user state in web applications. The "Permission denied (13)" error occurs when PHP cannot access or create session files due to permission issues, ownership problems, or misconfiguration.
The error occurs when PHP cannot access or create session files due to incorrect permissions, ownership, or misconfiguration in php.ini.
/var/lib/php/sessions/ (or custom session directory)/tmp/ or session directory1 First, determine where PHP stores session files by checking the configuration.
# Find which php.ini file is being used
php --ini | grep "Loaded Configuration File"
# Check the session directory configuration
php -i | grep "session.save_path"
# Alternative: Use a simple PHP command
php -r 'echo "Session path: " . session_save_path() . "\n";'
# Check all session-related configurations
php -i | grep -A 5 -B 5 session
session.save_path => /var/lib/php/sessions# Get the session path from PHP configuration
SESSION_PATH=$(php -r 'echo session_save_path();')
echo "Session directory: $SESSION_PATH"
# Check if directory exists
if [ -d "$SESSION_PATH" ]; then
echo "Directory exists."
echo "Current permissions:"
ls -ld "$SESSION_PATH"
echo ""
echo "Current owner and group:"
stat -c "%U %G" "$SESSION_PATH"
else
echo "Directory does NOT exist!"
echo "Creating directory structure..."
sudo mkdir -p "$SESSION_PATH"
fi
# Check what's inside the directory
if [ -d "$SESSION_PATH" ]; then
echo "Contents of session directory:"
ls -la "$SESSION_PATH" | head -20
fi
2 Grant correct permissions and ownership to the session directory.
# Standard permissions for session directory
sudo chmod -R 770 /var/lib/php/sessions
# Alternative permissions (more restrictive)
sudo chmod -R 750 /var/lib/php/sessions
# Set sticky bit to maintain ownership
sudo chmod +t /var/lib/php/sessions
# Verify permissions were set correctly
ls -ld /var/lib/php/sessions
echo "Permissions in octal:"
stat -c "%a %n" /var/lib/php/sessions
# Check all files in the directory
find /var/lib/php/sessions -type f -exec ls -la {} \; 2>/dev/null | head -10
# For Apache web server (Ubuntu/Debian)
sudo chown -R www-data:www-data /var/lib/php/sessions
# For Nginx web server (CentOS/RHEL)
sudo chown -R nginx:nginx /var/lib/php/sessions
# For PHP-FPM with Nginx (common setup)
# First, identify the PHP-FPM user
PHP_FPM_USER=$(grep "^user" /etc/php/8.0/fpm/pool.d/www.conf | awk '{print $3}' | head -1)
PHP_FPM_GROUP=$(grep "^group" /etc/php/8.0/fpm/pool.d/www.conf | awk '{print $3}' | head -1)
echo "PHP-FPM user: $PHP_FPM_USER"
echo "PHP-FPM group: $PHP_FPM_GROUP"
# Set ownership based on PHP-FPM configuration
if [ ! -z "$PHP_FPM_USER" ] && [ ! -z "$PHP_FPM_GROUP" ]; then
sudo chown -R $PHP_FPM_USER:$PHP_FPM_GROUP /var/lib/php/sessions
fi
# Verify ownership
ls -ld /var/lib/php/sessions
echo "Owner:Group format:"
stat -c "%U:%G" /var/lib/php/sessions
# For Apache
sudo systemctl restart apache2
# For Nginx with PHP-FPM
sudo systemctl restart nginx
sudo systemctl restart php8.0-fpm
# For standalone PHP-FPM
sudo systemctl restart php8.0-fpm
# Verify services are running without errors
sudo systemctl status apache2 --no-pager -l | head -30
sudo systemctl status nginx --no-pager -l | head -30
sudo systemctl status php8.0-fpm --no-pager -l | head -30
770 or 750 permissions for session directoriessetfacl -R -m u:www-data:rwx /var/lib/php/sessionsnamei -l /var/lib/php/sessions3 Security modules may block PHP from writing to the session directory.
# Check if SELinux is enabled
sestatus
getenforce
# Check SELinux context of session directory
ls -Z /var/lib/php/sessions
# Check SELinux denials in logs
sudo grep "denied" /var/log/audit/audit.log | grep php
sudo grep "denied" /var/log/audit/audit.log | grep httpd
sudo grep "avc:" /var/log/audit/audit.log | grep denied
# Use sealert for detailed analysis (if available)
sudo sealert -a /var/log/audit/audit.log 2>/dev/null | grep -A 10 -B 5 "denied" | head -50
# If SELinux is enabled, allow PHP to write sessions
sudo chcon -R -t httpd_sys_rw_content_t /var/lib/php/sessions
# Make the change permanent
sudo semanage fcontext -a -t httpd_sys_rw_content_t "/var/lib/php/sessions(/.*)?"
sudo restorecon -Rv /var/lib/php/sessions
# Alternative: Use boolean to allow HTTPD to write to all files
sudo setsebool -P httpd_unified 1
# Check the new context
ls -Z /var/lib/php/sessions
# Temporarily disable SELinux for testing (not recommended for production)
sudo setenforce 0
# To re-enable: sudo setenforce 1
# Check AppArmor status
sudo aa-status
# Check if PHP/php-fpm profiles are enforced
sudo aa-status | grep -i php
sudo aa-status | grep -i fpm
sudo aa-status | grep -i apache
sudo aa-status | grep -i nginx
# Put PHP-FPM in complain mode for testing
sudo aa-complain /usr/sbin/php-fpm8.0
# or for generic php-fpm
sudo aa-complain /usr/sbin/php-fpm
# Check AppArmor logs
sudo dmesg | grep -i apparmor | tail -20
sudo journalctl -xe | grep -i apparmor | tail -20
# List AppArmor profiles
sudo aa-status --enforced
sudo aa-status --complaining
setenforce 0 can help identify if SELinux is causing the issue, it should only be used temporarily for testing. Always restore proper SELinux contexts for production systems.
4 Insufficient disk space prevents PHP from creating new session files.
# Check overall disk usage
df -h
# Check specific partitions
df -h /var
df -h /tmp
df -h /
# Check inode usage (important for many small session files)
df -i
df -i /var
df -i /tmp
# Check directory sizes
sudo du -sh /var/lib/php/sessions/ 2>/dev/null
sudo du -sh /tmp/ 2>/dev/null
sudo du -sh /var/log/ 2>/dev/null
# Find largest files in /var
sudo find /var -type f -size +100M 2>/dev/null | xargs ls -lh 2>/dev/null | head -10
# If /var/lib/php/sessions is full, clear old sessions
sudo rm -rf /var/lib/php/sessions/*
# Alternative: Remove only old session files (older than 1 day)
sudo find /var/lib/php/sessions/ -type f -mtime +1 -delete
# Remove specific PHP session files
sudo find /tmp -name "sess_*" -delete 2>/dev/null
sudo find /var/lib/php/sessions -name "sess_*" -delete 2>/dev/null
# Clean package manager cache
sudo apt clean # Ubuntu/Debian
sudo yum clean all # CentOS/RHEL
# Clean log files (keep recent ones)
sudo journalctl --vacuum-time=7d
sudo find /var/log -type f -name "*.gz" -delete
sudo find /var/log -type f -name "*.log.*" -delete
# Check available space after cleanup
df -h /var
5 Multiple PHP versions can cause conflicts with session storage.
# Check current PHP version
php -v
# List all installed PHP versions
ls /etc/php/
# Check for multiple PHP packages
dpkg -l | grep php # Ubuntu/Debian
rpm -qa | grep php # CentOS/RHEL
# Check which PHP binary is used
which php
ls -la $(which php)
# Check PHP modules
php -m | grep session
php --info | grep -i "session module"
# Check PHP-FPM services
sudo systemctl list-units --type=service | grep php
sudo systemctl list-units --type=service | grep fpm
# Check specific PHP-FPM version status
sudo systemctl status php8.0-fpm --no-pager -l
sudo systemctl status php7.4-fpm --no-pager -l 2>/dev/null || echo "PHP 7.4 not installed"
# Check PHP-FPM configuration
ls -la /etc/php/*/fpm/pool.d/
cat /etc/php/8.0/fpm/pool.d/www.conf | grep -E "^(user|group|listen)"
# For Ubuntu/Debian with update-alternatives
sudo update-alternatives --config php
# For CentOS/RHEL (using remi repository)
sudo yum-config-manager --enable remi-php80
sudo yum update php
# Check Apache PHP module (if using mod_php)
apache2ctl -M | grep php # Ubuntu/Debian
httpd -M | grep php # CentOS/RHEL
# Disable conflicting PHP versions
sudo a2dismod php7.4 # Ubuntu/Debian
sudo a2enmod php8.0 # Ubuntu/Debian
# Restart web server after changes
sudo systemctl restart apache2
6 After applying fixes, restart services and test PHP sessions.
# Restart PHP-FPM
sudo systemctl restart php-fpm
# Restart web server
sudo systemctl restart apache2
# or
sudo systemctl restart nginx
# If using both Apache and PHP-FPM
sudo systemctl restart php8.0-fpm
sudo systemctl restart apache2
# Verify all services are running
sudo systemctl is-active php8.0-fpm
sudo systemctl is-active apache2
sudo systemctl is-active nginx
# Check for errors in logs immediately after restart
sudo tail -f /var/log/php8.0-fpm.log 2>/dev/null &
sudo tail -f /var/log/apache2/error.log 2>/dev/null &
# Create a test PHP file
sudo tee /var/www/html/test_session.php << 'EOF'
<?php
// Enable error reporting
ini_set('display_errors', 1);
error_reporting(E_ALL);
// Start session
session_start();
// Set a session variable
$_SESSION['test'] = 'Working!';
$_SESSION['timestamp'] = date('Y-m-d H:i:s');
$_SESSION['server'] = $_SERVER['SERVER_NAME'];
// Display session information
echo "<h2>PHP Session Test</h2>";
echo "<p>Session started successfully!</p>";
echo "<p>Session ID: " . session_id() . "</p>";
echo "<p>Session save path: " . session_save_path() . "</p>";
// Check if session file was created
$session_file = session_save_path() . '/sess_' . session_id();
if (file_exists($session_file)) {
echo "<p style='color: green;'>? Session file created: $session_file</p>";
echo "<p>File permissions: " . substr(sprintf('%o', fileperms($session_file)), -4) . "</p>";
} else {
echo "<p style='color: red;'>? Session file NOT created</p>";
}
// Display all session variables
echo "<h3>Session Variables:</h3>";
echo "<pre>";
print_r($_SESSION);
echo "</pre>";
// Test session persistence
if (isset($_SESSION['page_views'])) {
$_SESSION['page_views']++;
} else {
$_SESSION['page_views'] = 1;
}
echo "<p>Page views: " . $_SESSION['page_views'] . "</p>";
?>
EOF
# Test via command line first
php /var/www/html/test_session.php
# Check for any errors
if [ $? -eq 0 ]; then
echo "? PHP script executed successfully from command line"
else
echo "? PHP script failed from command line"
fi
# Get server IP for browser testing
SERVER_IP=$(hostname -I | awk '{print $1}')
echo "Test in browser: http://$SERVER_IP/test_session.php"
# Also test via curl
curl -s "http://localhost/test_session.php" | grep -E "(successfully|Session started|?|?)" | head -5
sudo tail -f /var/log/php_errors.log| Issue | Fix | Command/Solution |
|---|---|---|
| Incorrect folder permissions | Set proper permissions | sudo chmod -R 770 /var/lib/php/sessions |
| Wrong ownership | Change ownership | sudo chown -R www-data:www-data /var/lib/php/sessions |
| SELinux blocking access | Set SELinux context | sudo chcon -R -t httpd_sys_rw_content_t /var/lib/php/sessions |
| AppArmor restrictions | Put in complain mode | sudo aa-complain /usr/sbin/php-fpm |
| Full disk space | Clear session files | sudo rm -rf /var/lib/php/sessions/* |
| Multiple PHP versions causing conflicts | Switch PHP version | sudo update-alternatives --config php |
| Incorrect php.ini configuration | Update session.save_path | Edit /etc/php/8.0/fpm/php.ini |
| Web server user mismatch | Check service configurations | Verify Apache/Nginx/PHP-FPM user settings |
| Directory doesn't exist | Create directory | sudo mkdir -p /var/lib/php/sessions |
| ACL restrictions | Check and set ACLs | getfacl /var/lib/php/sessions |
php -i | grep session.save_pathBy following these systematic fixes, server administrators can resolve PHP session permission issues and restore full session functionality to their web applications.