Diagnosing Moodle Cron Execution Failures
A step-by-step guide to identify why Moodle cron does not run, apply targeted fixes, verify success, and know when to escalate.
03 Apr 2026, 00:19 UTC

Recognizing the condition
Moodle scheduled tasks (forum digests, activity completion, quiz timing, badge awards) are not being processed. In Site administration → Reports → Cron you see one or more of:
- No new timestamp entries for several expected intervals.
- Warnings such as "Cron script did not complete successfully" or "Last run was more than X minutes ago".
- Empty or error-filled output when you invoke the cron script manually.
These signs mean the cron mechanism — either the CLI script (admin/cli/cron.php) or the web-based fallback (admin/cron.php) — is failing to start or terminating prematurely. Do not simply disable cron while investigating: without it, digests, completions, and timed quiz behavior all break.
Symptom-to-cause table
| Symptom | Likely cause |
|---|---|
| No new entries in cron log; manual CLI run returns nothing or a permission error | CLI script not executable, or wrong PHP binary path |
| Manual CLI run produces PHP fatal errors or blank output | Missing PHP extensions, memory_limit too low, or max_execution_time too short |
HTTP 500 when requesting admin/cron.php in a browser | Web server PHP misconfiguration (PHP-FPM down, faulty rewrite rules) |
Cron appears to run but tasks stay stale; ps aux shows multiple identical cron processes | Overlapping cron instances from over-frequent scheduling or lock failure |
| Cron stops after a few seconds with no Moodle error | Server-level limits (hosting timeout, OOM killer, resource caps) |
Ordered checks
- Verify the CLI cron command. On the server, as the user that owns the Moodle files or the web user (e.g.,
www-data), run from anywhere:php /path/to/moodle/admin/cli/cron.phpReplace
/path/to/moodlewith your Moodle root. A successful run ends withCron script completed successfully. "Command not found" means PHP is not in that user's PATH; "Permission denied" means the file is not executable/readable by that user. - Check file permissions.
ls -l /path/to/moodle/admin/cli/cron.phpThe file should be readable by the cron user. If you invoke it directly (
./admin/cli/cron.php) it also needs the execute bit; invoking viaphponly requires read access. On shared hosting, confirm with your provider before changing modes. - Inspect server and PHP logs. After a failed run, check the web server error log (e.g.,
/var/log/apache2/error.logor/var/log/nginx/error.log), the PHP-FPM log if applicable, and the system log for OOM-killer messages. Look for lines referencingadmin/cli/cron.php. - Check for duplicate cron processes.
ps aux | grep '[a]dmin/cli/cron.php'More than one line suggests a previous run is still alive (long task or lock failure). Note the PIDs.
- Test the web-based cron URL. From a client or via curl on the server:
curl -i https://yourmoodle.example.com/admin/cron.phpExpect HTTP 200 and a body indicating the cron process executed. A 500, 403, or 404 points to web server or PHP-FPM misconfiguration. Note: on many Moodle versions web cron is disabled by default or requires a password set in
config.php($CFG->cronremotepassword); check Site administration → Security → Site policies for the cron settings. - Review PHP limits. Run
php -i | grep -E 'max_execution_time|memory_limit'for the CLI configuration and compare with Site administration → Server → PHP info. CLI PHP often uses a differentphp.inithan the web SAPI, so a limit that looks fine in the browser may still kill CLI cron.
Fixes tied to findings
- Wrong PHP path or permissions: specify the full PHP binary in the cron job, e.g.
/usr/bin/php /path/to/moodle/admin/cli/cron.php, and ensure the cron user can read the script. Adjust withchmodas the file owner or root if needed. - PHP limits too low: edit the CLI
php.ini(find it withphp --ini):max_execution_time = 600 memory_limit = 256MRe-run the CLI command to confirm the new values apply. CLI
max_execution_timedefaults to 0 (unlimited) on many distributions; only change it if it has been restricted. - Stale or overlapping processes: terminate lingering runs with
kill <PID>(use-9only if a normal kill fails). Then reduce scheduling frequency; on shared hosting avoid intervals under 5 minutes, since aggressive scheduling can trip provider resource limits. Moodle's built-in locking normally prevents overlap, so persistent duplicates suggest a task is hanging — check which task in the cron report. - Web cron returning 500/403: confirm the PHP-FPM pool is running (
systemctl status php-fpmor the version-specific unit), verify the web server passes.phprequests to PHP correctly, and check that no access rule blocksadmin/cron.php. Reload the web server after changes and retest with curl. - No scheduler entry at all: add a system crontab line for the appropriate user:
*/5 * * * * /usr/bin/php /path/to/moodle/admin/cli/cron.php >> /var/log/moodle_cron.log 2>&1Adjust the interval to your site's needs and hosting constraints. Moodle 4.x also supports ad-hoc task runners; CLI cron remains the standard trigger.
Escalation criteria
- After applying the relevant fix, run the CLI cron manually twice more. If it still fails (non-zero exit, error output, or no success message), gather: the full CLI output, the web server/PHP-FPM log lines covering the failure window, and
ps aux | grep cronoutput. - Treat core Moodle exceptions or PHP fatals in the logs (undefined function calls, out-of-memory, database connection errors) as a deeper platform problem rather than a cron scheduling issue.
- Forward the collected logs and a list of steps already taken to your system administrator or to the Moodle community forums / support channels.
Verifying the fix
- Run
php /path/to/moodle/admin/cli/cron.phpmanually and confirm it completes without errors. - Open Site administration → Reports → Cron: the latest run timestamp should be recent and no error entries should appear.
- If you use web cron, repeat the curl request and confirm HTTP 200 with the expected body.
- After a run, check
ps aux | grep cronto confirm no orphaned PHP processes remain.
Working through these checks in order isolates whether the failure lives in the CLI environment, permissions, PHP limits, overlapping instances, or the web server configuration — so each fix is tied to evidence rather than guesswork.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.