Fixing PHP session_start(): Permission Denied (13) Error
1. What Does This Error Mean?
The error occurs when PHP cannot access or create session files due to incorrect permissions, ownership, or misconfiguration in php.ini.
For closely related session_start permission topics, see session_start() failed: Permission denied (13) (sysadmin guide), Failed to Read Session Data (read-side), Verify PHP Configuration (php.ini), and phpMyAdmin "Error During Session Start".
Common Causes:
- Incorrect folder permissions on
/var/lib/php/sessions/(or custom session directory) - Wrong ownership (Apache/Nginx cannot write session files)
- SELinux or AppArmor restrictions preventing access
- Insufficient disk space in
/tmp/or session directory - Multiple PHP versions conflicting with session storage
2. Find the PHP Session Directory
First, determine where PHP stores session files by checking the configuration.
Check php.ini Configuration
Find Active php.ini File and Session Path
# 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/sessionsIf the directory is missing or incorrect, note the path and proceed to fix it in the following steps.
Verify Directory Existence and Permissions
Check Session Directory Status
# 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
3. Fix Directory Permissions
Grant correct permissions and ownership to the session directory.
Grant Correct Permissions
Set Proper Directory Permissions
# 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
Ensure Correct Ownership
Set Proper Ownership for Session Directory
# 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
Test by Restarting Apache/Nginx
Restart Web Services and Test
# 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
- Use
770or750permissions for session directories - Ensure the web server user (www-data, nginx, apache) owns the directory
- Consider using ACLs for more granular control:
setfacl -R -m u:www-data:rwx /var/lib/php/sessions - Regularly audit permissions with:
namei -l /var/lib/php/sessions
4. Check for SELinux/AppArmor Restrictions
Security modules may block PHP from writing to the session directory.
Check SELinux Status
Diagnose SELinux Issues
# 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
Fix SELinux Context
Allow PHP to Write Sessions with SELinux
# 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 (Ubuntu/Debian)
Diagnose AppArmor Restrictions
# 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.
5. Verify Disk Space
Insufficient disk space prevents PHP from creating new session files.
Check Disk Usage
Monitor Disk Space and Inodes
# 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
Clear Old Sessions and Free Space
Clean Up Disk Space
# 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
6. Check for Multiple PHP Versions
Multiple PHP versions can cause conflicts with session storage.
Check Installed PHP Versions
Identify PHP Versions on System
# 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"
Verify Running PHP-FPM Versions
Check Active PHP-FPM Services
# 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)"
Switch Default PHP Version if Needed
Change Active PHP Version
# 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
7. Restart and Test
After applying fixes, restart services and test PHP sessions.
Restart PHP and Web Server
Complete Service Restart
# 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 Test Script
Test PHP Session Functionality
# 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 Session Script
Test the Session Script
# 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
- Test with different browsers to rule out browser-specific cookie issues
- Clear browser cookies between tests if needed
- Check both HTTP and HTTPS if your site uses SSL
- Monitor server logs while testing:
sudo tail -f /var/log/php_errors.log
8. Summary of Fixes
| 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 |
- Identify the session directory with
php -i | grep session.save_path - Check if directory exists and has correct permissions
- Verify ownership matches web server user
- Check for SELinux/AppArmor restrictions
- Ensure sufficient disk space and inodes
- Confirm consistent PHP version usage
- Test with a simple session script
- Check server logs for any remaining errors
By following these systematic fixes, server administrators can resolve PHP session permission issues and restore full session functionality to their web applications.


