Sửa lỗi PHP Fatal Error: Maximum Execution Time of 30 Seconds Exceeded

beginner🐘 PHP2026-03-25| PHP 7.x/8.x trên Linux/Windows, Apache, Nginx + PHP-FPM, Laravel, WordPress, shared hosting (cPanel), VPS

Error Message

Fatal error: Maximum execution time of 30 seconds exceeded
#php#timeout#execution-time#max-execution

Lỗi Gặp Phải

Script của bạn chạy đến đây rồi dừng hẳn:

Fatal error: Maximum execution time of 30 seconds exceeded in /var/www/html/process.php on line 142

PHP có giới hạn thời gian thực thi tích hợp sẵn (max_execution_time) — mặc định là 30 giây. Khi script chạy quá thời gian này, PHP sẽ kill nó. Không dọn dẹp, không thoát êm đẹp. Chỉ là chết thẳng.

Bạn thường gặp lỗi này khi import CSV số lượng lớn, gọi đến API bên thứ ba chậm chạp, tạo PDF/báo cáo, pipeline resize ảnh, hoặc bất kỳ vòng lặp nào duyệt qua hàng nghìn dòng trong database.

Nguyên Nhân Gốc Rễ

Script đang làm quá nhiều việc trong một HTTP request duy nhất. Hoặc là logic bản thân chạy chậm, hoặc nó đang bị chặn chờ thứ gì đó bên ngoài — một câu query DB mất 10 giây, một API không phản hồi, một file 200 MB được load toàn bộ vào bộ nhớ.

Một điểm cần phân biệt rõ: PHP CLI (php script.php) mặc định max_execution_time = 0 — không giới hạn. Lỗi này gần như chỉ xảy ra trong môi trường web (Apache hoặc Nginx đang phục vụ HTTP request).

Cách Sửa 1: Tăng Giới Hạn Trong php.ini

Cách sửa lâu dài nhất. Áp dụng toàn cục cho server. Trước tiên, tìm file php.ini đang hoạt động:

php --ini | grep 'Loaded Configuration'
# hoặc
php -r "echo php_ini_loaded_file();"

Chỉnh sửa và tăng giới hạn lên:

; php.ini
max_execution_time = 120

Sau đó khởi động lại web server:

# Apache
sudo systemctl restart apache2

# Nginx + PHP-FPM
sudo systemctl restart php8.2-fpm
sudo systemctl restart nginx

Tránh đặt giá trị 0 cho các script phục vụ web. Thời gian thực thi không giới hạn có nghĩa là một request chậm có thể chiếm giữ PHP-FPM worker mãi mãi — đó là mầm mống của một cuộc tấn công DoS.

Cách Sửa 2: Đặt Trực Tiếp Trong Script (Override Nhanh)

Không thể chỉnh php.ini? Shared hosting, server của người khác, hotfix khẩn cấp lúc 2 giờ sáng — set_time_limit() hoạt động mà không cần quyền truy cập cấu hình:

<?php
// Đặt dòng này ở đầu script
set_time_limit(120); // 120 giây

// Hoặc reset đồng hồ trong mỗi vòng lặp
foreach ($large_dataset as $item) {
    set_time_limit(30); // Reset về 30 giây cho mỗi item
    process($item);
}

set_time_limit(0) vô hiệu hóa hoàn toàn giới hạn cho lần chạy script đó. Ổn với batch job CLI xử lý 50.000 bản ghi. Không ổn với một endpoint công khai bất kỳ.

Lưu ý: set_time_limit() không có tác dụng nếu PHP chạy ở chế độ safe mode — hiếm gặp trong các hệ thống hiện đại, nhưng đáng biết nếu bạn đang dùng hạ tầng cũ.

Cách Sửa 3: Override Qua .htaccess (Chỉ Dành Cho Apache)

Trên shared hosting Apache có bật AllowOverride, bạn có thể đặt giới hạn theo từng thư mục mà không cần chỉnh bất kỳ thứ gì ở cấp global:

# .htaccess
php_value max_execution_time 120

Không cần khởi động lại. Apache đọc .htaccess theo mỗi request.

Cách Sửa 4: php.ini Trong Thư Mục Gốc Dự Án (cPanel / Một Số Host)

Nhiều shared host cho phép bạn đặt file php.ini hoặc .user.ini trực tiếp trong thư mục dự án:

# public_html/php.ini  HOẶC  public_html/.user.ini
max_execution_time = 120

Kiểm tra tài liệu của host để biết họ đọc file nào. .user.ini là tương đương PHP-FPM và phổ biến hơn trên các host chạy stack hiện đại.

Cách Sửa 5: Cấu Hình PHP-FPM Pool

Đang chạy PHP-FPM trực tiếp? Override giới hạn theo từng pool thay vì chỉnh php.ini toàn cục:

# /etc/php/8.2/fpm/pool.d/www.conf
php_admin_value[max_execution_time] = 120

Khởi động lại dịch vụ FPM để áp dụng:

sudo systemctl restart php8.2-fpm

Cách Sửa 6: Dành Cho Laravel / Artisan Commands

Với queued job hoặc Artisan command chạy lâu, đặt giới hạn ở đầu method handle():

<?php
public function handle()
{
    set_time_limit(0); // CLI vốn bỏ qua điều này, nhưng tường minh hơn là ngầm hiểu
    ini_set('max_execution_time', 0);

    // logic chạy lâu của bạn
}

Cũng cần kiểm tra timeout của queue worker — giới hạn của PHP và timeout worker của Laravel là hai đồng hồ riêng biệt:

# Chạy worker với timeout tường minh (đơn vị giây)
php artisan queue:work --timeout=120

Cách Sửa 7: Chẩn Đoán và Sửa Code Chậm

Tăng giới hạn chỉ là mua thêm thời gian. Nó không sửa gốc rễ vấn đề. Nếu script của bạn thực sự cần 5 phút, đó là dấu hiệu đỏ cần điều tra.

Bắt đầu bằng cách đo xem thời gian thực sự tiêu tốn ở đâu:

<?php
$start = microtime(true);

// ... khối code của bạn ...

$elapsed = microtime(true) - $start;
error_log("Block A mất: {$elapsed}s");

Các thủ phạm thường gặp:

  • Query DB chậm — chạy EXPLAIN để kiểm tra. Thiếu index trên bảng 500.000 dòng có thể biến query 10ms thành table scan mất 45 giây.
  • Gọi API bên ngoài — luôn đặt timeout tường minh: curl_setopt($ch, CURLOPT_TIMEOUT, 10). Không có nó, PHP sẽ chờ vô thời hạn với server không bao giờ phản hồi.
  • Xử lý file lớn — stream thay vì load toàn bộ vào bộ nhớ cùng lúc. Đọc file 1 GB bằng file_get_contents() sẽ cạn kiệt cả bộ nhớ lẫn thời gian.
  • Vòng lặp lồng nhau trên mảng lớn — logic O(n²) nhanh chóng đụng tường. Hãy dùng chunking hoặc xem lại thuật toán.

Với các tác vụ xử lý hàng loạt, giải pháp thực sự là đưa chúng ra khỏi HTTP request:

<?php
// Đừng xử lý 10.000 dòng đồng bộ trong một web request.
// Đẩy vào job và trả về ngay.
ImportJob::dispatch($file_path);

return response()->json(['status' => 'processing']);

Xác Nhận Đã Sửa Được

Đừng tin vào những gì bạn đặt — hãy xác nhận giá trị thực sự đang hoạt động ở runtime:

<?php
echo ini_get('max_execution_time');

Hoặc dùng phpinfo() (đừng bao giờ để lại trên production) và tìm kiếm max_execution_time. Bạn sẽ thấy cả giá trị master lẫn giá trị local. Nếu chúng khác nhau, có thứ gì đó đang ghi đè cài đặt của bạn — kiểm tra .htaccess, pool config, hoặc .user.ini theo thứ tự đó.

Chạy lại script bị lỗi và xác nhận nó hoàn thành mà không còn fatal error.

Tham Khảo Nhanh

  • php.inimax_execution_time = 120 (toàn cục, cần khởi động lại)
  • Đầu scriptset_time_limit(120); (theo từng script, áp dụng ngay)
  • .htaccess (Apache)php_value max_execution_time 120 (không cần khởi động lại)
  • .user.inimax_execution_time = 120 (PHP-FPM theo từng thư mục)
  • CLI — mặc định là 0 (không giới hạn), lỗi này sẽ không xảy ra ở đó

Phòng Ngừa

Mô hình gây ra lỗi này khá dễ đoán: công việc đồng bộ, blocking bên trong một HTTP request. Hãy phá vỡ mô hình đó sớm.

Thêm logging thời gian thực thi vào bất kỳ tiến trình nào kết nối với hệ thống bên ngoài. Thiết lập giám sát request chậm — biến format %D của Apache ghi lại thời gian request theo microsecond; New Relic và Datadog có thể cảnh báo khi một route liên tục chạm ngưỡng 10+ giây.

Theo nguyên tắc chung: một web request nên trả về trong vòng dưới 3 giây. Nếu bạn cần 30 giây trở lên, công việc đó thuộc về background job — queue worker, cron task, hoặc async process. HTTP response chỉ nên trả về "Tôi đã đưa vào hàng chờ" và kết thúc ngay lập tức.

Related Error Notes