Introduction

PHP's default file-based session handler stores session data as files in a temporary directory (usually /tmp or /var/lib/php/sessions). When the web server user (www-data, nginx, apache) lacks write permission to this directory, session operations fail with "Permission denied" errors, causing users to be unable to log in or maintain state.

This issue commonly occurs after server migrations, permission changes, or when deploying to new environments with different user configurations.

Symptoms

  • Users cannot log in -- sessions are not persisted between requests
  • Error log shows "session_start(): open(/tmp/sess_xxx, O_RDWR) failed: Permission denied"
  • Session files exist but are owned by a different user than the web server process

Common Causes

  • /tmp or session save path has restrictive permissions (not 1777)
  • Session files were created by a different user (e.g., CLI script run as root)
  • SELinux or AppArmor blocks PHP from writing to the session directory

Step-by-Step Fix

  1. 1.Fix session directory permissions: Ensure the web server can write to the session path.
  2. 2.```bash
  3. 3.# Check current session save path:
  4. 4.php -r "echo session_save_path() . PHP_EOL;"
  5. 5.# or check php.ini:
  6. 6.grep session.save_path /etc/php/8.2/fpm/php.ini

# Fix permissions on the session directory: sudo chmod 1777 /tmp # or for dedicated session directory: sudo chown -R www-data:www-data /var/lib/php/sessions sudo chmod 770 /var/lib/php/sessions ```

  1. 1.Configure a dedicated session directory: Use a path controlled by your application.
  2. 2.```php
  3. 3.<?php
  4. 4.// Set before session_start()
  5. 5.$sessionPath = '/var/www/myapp/sessions';
  6. 6.if (!is_dir($sessionPath)) {
  7. 7.mkdir($sessionPath, 0770, true);
  8. 8.}
  9. 9.session_save_path($sessionPath);
  10. 10.session_start();
  11. 11.`
  12. 12.Switch to Redis or database session handler: More reliable for production.
  13. 13.```php
  14. 14.<?php
  15. 15.// Redis session handler (requires php-redis extension):
  16. 16.ini_set('session.save_handler', 'redis');
  17. 17.ini_set('session.save_path', 'tcp://127.0.0.1:6379?auth=secret');
  18. 18.session_start();

// Or in php.ini: // session.save_handler = redis // session.save_path = "tcp://127.0.0.1:6379" ```

Prevention

  • Use Redis or Memcached for session storage in production
  • Set up a dedicated session directory with correct ownership during deployment
  • Monitor session directory disk usage and implement cleanup cron jobs
  • Include session write tests in your deployment verification process