Stale doing_cron Transient: Releasing the WP-Cron Lock

When the doing_cron transient stays locked, every scheduled task stops. Here is how to clear it and find the root cause.

WordPress uses a transient called doing_cron as a simple mutex preventing two cron processes from running in parallel. When a process starts it sets the value to the current time; when it finishes it deletes the transient. If the process is interrupted, the lock remains and everything freezes.

Why this matters

WordPress's cron code checks doing_cron before each run. If the transient exists and its value is younger than WP_CRON_LOCK_TIMEOUT seconds (default 60), WordPress assumes another worker is currently running and skips. That is correct under normal conditions; but if a cron run is killed mid-execution (PHP fatal, OOM, PHP timeout, PHP-FPM restart) the transient can be left behind with an option_value that is never cleaned up. Every subsequent cron request assumes work is in progress and skips. The result: backups, syncs, scheduled post publishing, emails - everything simply stops. And it is not always obvious - there is no error on screen, just silence in the background.

How to detect

Check the transient via WP-CLI:

wp transient get doing_cron

If it returns a timestamp far older than 60 seconds (an hour ago, a day ago) it is stuck. SQL alternative:

SELECT option_name, option_value FROM wp_options WHERE option_name LIKE '%doing_cron%';

wp cron event list showing every hook with a negative next_run_relative is also an indirect sign.

How to fix

  1. The recommended path: wp transient delete doing_cron. This also clears the timeout entry.
  2. SQL alternative:
    DELETE FROM wp_options WHERE option_name IN ('_transient_doing_cron', '_transient_timeout_doing_cron');
  3. UI alternative: install the free Transients Manager, search for doing_cron and click Delete.
  4. After deletion enable WP_DEBUG and WP_DEBUG_LOG in wp-config.php and wait. The root cause - the fatal that caused the lock - will appear in debug.log.
  5. Fix the offending code or remove the plugin. For third-party plugins file an upstream issue.
  6. If it recurs frequently, switch to system cron (see wp_cron_status). This removes the dependency on a forgotten lock.

Common mistakes

  • Repeatedly clearing without investigating: simply deleting the transient each time is symptomatic, not curative. The problem will return.
  • Lowering WP_CRON_LOCK_TIMEOUT too far: this causes two parallel workers to fight over the same task. The default (60) is fine.
  • Blaming cron when PHP-FPM is the real cause: OOM errors invite suspicion of WP-Cron, but the actual issue is PHP memory exhaustion. Raise memory_limit in wp-config.php.
  • Skipping verification: deletion can succeed only for the lock to reappear within five minutes if the underlying issue persists. Re-check.

Verifying the fix

Run wp cron event run --due-now - overdue events should fire. Run wp transient get doing_cron - should be empty or fresh. Wait 10-30 minutes and verify a backup, an email or a scheduled post completes at the expected moment. RankPlus will return to green.

Tip: If you see doing_cron getting stuck several times a week, it is almost always Action Scheduler from WooCommerce dying mid-batch. Clear stuck actions with wp action-scheduler clean and raise memory_limit to at least 512M.