Cron is the Linux task scheduler that runs commands at specified times without any human intervention. Every Linux server has a cron daemon running in the background that reads crontab files and executes commands when their scheduled time arrives. For WordPress server management, cron is essential for automating database backups, cleaning up old log files, running WP-CLI maintenance commands like wp cron event run --due-now to replace the unreliable browser-triggered WP-Cron, optimising database tables nightly, and rotating the debug.log file before it fills the disk. The crontab syntax has five time fields followed by the command: minute (0-59), hour (0-23), day of month (1-31), month (1-12), and day of week (0-7, where both 0 and 7 represent Sunday). Each field accepts a specific number, an asterisk (*) for every unit, a comma-separated list, a range with a dash, or a step value with a slash — for example */15 means every 15 units. There are also shorthand aliases: @daily, @weekly, @monthly, and @reboot. Cron jobs run in a minimal environment without the normal shell variables, so always use absolute paths for both the command binary and any file arguments, and explicitly set PATH or HOME at the top of the crontab if needed. Redirect output to a log file or to /dev/null to prevent cron from sending email notifications for every run. The MAILTO="" variable at the top of the crontab suppresses all email output globally. Pair system cron with the backup script guide and the server monitoring guide for a complete maintenance automation setup.
Problem: WordPress maintenance tasks like database backups, WP-Cron execution, and log cleanup run inconsistently or not at all because they depend on browser traffic to trigger them.
Solution: Replace browser-triggered WP-Cron with system cron and schedule all maintenance tasks in the server crontab:
# Edit the crontab for the current user
crontab -e
# View current crontab
crontab -l
# Crontab syntax:
# MIN HOUR DOM MON DOW COMMAND
# * * * * * /path/to/command
# Suppress all cron email notifications
MAILTO=""
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# Replace WP-Cron — run every 5 minutes via WP-CLI
*/5 * * * * /usr/local/bin/wp --path=/var/www/html/wordpress cron event run --due-now --quiet
# Daily database backup at 02:00 AM
0 2 * * * /var/www/html/wordpress/backup.sh >> /var/log/wp-backup.log 2>&1
# Weekly database optimisation on Sunday at 03:00 AM
0 3 * * 0 /usr/local/bin/wp --path=/var/www/html/wordpress db optimize --quiet
# Clear expired WordPress transients daily at 04:00 AM
0 4 * * * /usr/local/bin/wp --path=/var/www/html/wordpress transient delete --expired --quiet
# Rotate debug.log weekly — truncate if over 50MB
0 1 * * 1 find /var/www/html/wordpress/wp-content -name 'debug.log' -size +50M -exec truncate -s 0 {} \;
# Restart PHP-FPM every night at 05:00 AM to clear memory leaks
0 5 * * * /bin/systemctl restart php8.1-fpm >> /var/log/php-fpm-restart.log 2>&1
// Disable the default browser-triggered WP-Cron in wp-config.php
// (add BEFORE the "That's all" line)
// This prevents a cron HTTP request on every page load
define( 'DISABLE_WP_CRON', true );
NOTE: When using WP-CLI in cron, always pass the full --path= argument pointing to the WordPress root because cron does not have a working directory context. If WP-CLI is installed via Composer rather than globally, replace /usr/local/bin/wp with the full path to the Phar file, e.g. /var/www/html/wordpress/vendor/bin/wp. After adding define( ‘DISABLE_WP_CRON’, true ) to wp-config.php, verify that the system cron job is actually running with grep CRON /var/log/syslog | tail -20 to avoid missing scheduled posts and plugin jobs.