Lỗi Gặp Phải
Ứng dụng của bạn đang ghi lỗi này vào log:
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions)
Warning: session_start(): open(SESSION_PATH/sess_abc123, O_RDWR) failed: Permission denied (13)
Đôi khi đi kèm với:
Warning: session_start(): Failed to read session data: files (path: /tmp)
Người dùng bị đăng xuất ngẫu nhiên, giỏ hàng bị xóa sạch, form đăng nhập không lưu được trạng thái. Đây là lỗi session điển hình xảy ra vào thời điểm tệ nhất có thể.
Nguyên Nhân
PHP ghi dữ liệu session xuống đĩa. Tiến trình chạy PHP — thường là www-data, apache, hoặc nginx — không có quyền ghi vào đường dẫn lưu session, hoặc thư mục đó hoàn toàn không tồn tại.
Ba nguyên nhân phổ biến gây ra lỗi này:
- Sai owner của thư mục session (phổ biến nhất)
- Sai quyền truy cập — thư mục tồn tại nhưng user của PHP không ghi được
- Sai đường dẫn trong
php.initrỏ đến nơi không tồn tại
Trên Ubuntu/Debian, các pool của PHP-FPM chạy dưới user www-data. Nhưng sau khi nâng cấp distro hoặc cài lại package thủ công, thư mục session thường bị đặt lại về quyền sở hữu của root — và đột nhiên mọi thứ ngừng hoạt động.
Bước 1 — Xác Định Đường Dẫn Session
Kiểm tra PHP đang thực sự lưu session vào đâu:
php -r "echo session_save_path();"
Hoặc từ một file PHP:
<?php echo ini_get('session.save_path'); ?>
Cũng kiểm tra trong php.ini:
php --ini
grep -r 'session.save_path' /etc/php/
Các đường dẫn phổ biến cần kiểm tra:
/var/lib/php/sessions(mặc định trên Ubuntu/Debian)/tmp/var/lib/php/session(CentOS/RHEL)- Đường dẫn tùy chỉnh được đặt trong cấu hình pool hoặc
php.ini
Bước 2 — Kiểm Tra Owner và Quyền Truy Cập
ls -la /var/lib/php/sessions
Bạn có thể thấy kết quả như sau:
drwx-wx-wt 2 root root 4096 Apr 1 02:14 sessions
Kiểm tra user mà PHP-FPM đang chạy:
ps aux | grep php-fpm | grep -v grep
Hoặc kiểm tra trực tiếp trong cấu hình pool:
grep -E '^user|^group' /etc/php/8.*/fpm/pool.d/www.conf
Cách Sửa 1 — Sửa Owner (Phổ Biến Nhất)
Nếu PHP-FPM chạy với user www-data:
sudo chown root:www-data /var/lib/php/sessions
sudo chmod 770 /var/lib/php/sessions
Trên CentOS/RHEL khi PHP-FPM chạy với user apache:
sudo chown root:apache /var/lib/php/sessions
sudo chmod 770 /var/lib/php/sessions
Ubuntu đặt sticky bit (+t) theo mặc định — hãy giữ nguyên. Nó ngăn một user xóa file session của user khác:
sudo chmod 1770 /var/lib/php/sessions
Cách Sửa 2 — Thư Mục Không Tồn Tại
Các bản cập nhật package đôi khi xóa hoàn toàn thư mục này. Hãy tạo lại:
sudo mkdir -p /var/lib/php/sessions
sudo chown root:www-data /var/lib/php/sessions
sudo chmod 1770 /var/lib/php/sessions
Cách Sửa 3 — Dùng Đường Dẫn Session Riêng Cho Từng Ứng Dụng
Không thể chỉnh sửa thư mục hệ thống? Đang chạy nhiều ứng dụng dưới các user khác nhau? Hãy đặt đường dẫn session tùy chỉnh cho từng ứng dụng:
<?php
$sessionDir = __DIR__ . '/../storage/sessions';
if (!is_dir($sessionDir)) {
mkdir($sessionDir, 0700, true);
}
session_save_path($sessionDir);
session_start();
Đặt thư mục này ngoài web root — không được truy cập được qua HTTP. Sau đó xác nhận quyền ghi:
ls -la storage/sessions/
Cách Sửa 4 — Cấu Hình Ở Cấp Pool PHP-FPM
Thay vì chỉnh php.ini toàn cục, hãy đặt đường dẫn session trong cấu hình pool. Cách này giúp cô lập session theo từng virtual host:
# /etc/php/8.2/fpm/pool.d/myapp.conf
[myapp]
user = www-data
group = www-data
php_value[session.save_path] = /var/lib/php/sessions/myapp
Sau đó tạo thư mục và cấp quyền:
sudo mkdir -p /var/lib/php/sessions/myapp
sudo chown www-data:www-data /var/lib/php/sessions/myapp
sudo chmod 700 /var/lib/php/sessions/myapp
sudo systemctl restart php8.2-fpm
Cách Sửa 5 — SELinux Chặn Quyền Ghi (CentOS/RHEL)
Quyền truy cập trông có vẻ đúng nhưng session vẫn lỗi trên CentOS/RHEL? SELinux có thể đang âm thầm chặn các thao tác ghi. Kiểm tra audit log:
sudo ausearch -m avc -ts recent | grep php
Nếu thấy các lần từ chối, hãy khôi phục ngữ cảnh SELinux đúng:
sudo restorecon -R /var/lib/php/sessions
Hoặc chuyển tạm sang chế độ permissive để xác nhận SELinux là thủ phạm:
sudo setenforce 0
# kiểm tra session
sudo setenforce 1
Xác Nhận Đã Sửa Xong
Đến lúc kiểm tra xem có thực sự hoạt động không. Chạy script test này ngay sau khi áp dụng cách sửa:
<?php
session_start();
$_SESSION['test'] = 'ok';
echo 'Session ID: ' . session_id() . PHP_EOL;
echo 'Save path: ' . session_save_path() . PHP_EOL;
echo 'Status: ' . (session_status() === PHP_SESSION_ACTIVE ? 'ACTIVE' : 'FAILED');
Sau đó kiểm tra xem file session có thực sự được tạo không:
ls -la /var/lib/php/sessions/
Bạn sẽ thấy các file có dạng sess_abc123xyz với timestamp gần đây. Nếu thư mục trống sau khi chạy test, nghĩa là việc ghi vẫn đang thất bại.
Theo dõi PHP error log theo thời gian thực trong khi test:
sudo tail -f /var/log/php8.2-fpm.log
# hoặc
sudo journalctl -u php8.2-fpm -f
Mẹo Hữu Ích
Không chắc chmod 1770 hay 770 thực sự cấp quyền gì lúc 2 giờ sáng? Unix Permissions Calculator trên ToolCraft cho phép bạn trực quan hóa các bit phân quyền ngay lập tức — trước khi vô tình mở quá rộng hoặc khóa PHP ra ngoài hoàn toàn.
Phòng Ngừa
- Thêm healthcheck: Một cron job chạy mỗi 5 phút để kiểm tra thư mục session có tồn tại và ghi được không — và gửi cảnh báo — sẽ phát hiện vấn đề trước khi người dùng gặp phải.
- Cố định đường dẫn trong php.ini: Đừng dựa vào giá trị mặc định. Đặt tường minh
session.save_pathđể nó không bao giờ âm thầm thay đổi sau khi nâng cấp package. - Dùng Redis hoặc Memcached cho session trên các site có hàng trăm người dùng đồng thời:
session.save_handler = redisvớisession.save_path = "tcp://127.0.0.1:6379"loại bỏ hoàn toàn các vấn đề phân quyền filesystem. - Giám sát lỗi session: Thiết lập cảnh báo log cho chuỗi
session_start(): Failedđể phát hiện sự cố trước khi người dùng báo cáo. - Sau khi nâng cấp OS: Luôn chạy
ls -la /var/lib/php/sessions— các bản cập nhật package đôi khi đặt lại owner về root.

