The short answer
When Magento 2 cron appears to stop, first identify whether the scheduler failed to launch Magento, Magento stopped creating the expected schedule, or a particular task stopped completing. Reinstalling cron cannot repair every failure in that chain.
Start with the affected outcome: delayed asynchronous order emails, stale scheduled indexes, an integration backlog or a missed custom export. Record the job code, expected frequency and first known failure. If you need the wider operational picture, use our Magento 2 health-check guide.
Choose your evidence
Which failure pattern do you have?
This local decision aid suggests the next investigation. It does not connect to your store or diagnose it automatically.
Start with the evidence window
Record the affected job and expected frequency. Use the bounded SQL queries below against the primary application database; compare two snapshots. Avoid interpreting a missing row without checking retention and the expected schedule.
Go to the relevant checks →Scope, assumptions and command safety
This guide targets Linux-hosted Magento Open Source and Adobe Commerce 2.4.x. Commands and SQL are documentation-reviewed examples, not a test certificate for every release or hosting model.
- Run Magento CLI commands as the filesystem owner in the active application root. Substitute the deployment’s actual PHP binary for
php. - Shell inspections and SQL SELECTs below do not intentionally change store configuration. Application bootstrap may still write logs or generated files.
- Run SQL through an existing authorized database client, preferably with a read-only account. Use the primary application database; replicas may lag. Replace
cron_schedulewith the prefixed table name where applicable. - Keep credentials, customer details and raw exception messages out of public reports. The bounded queries deliberately omit the messages column.
Adobe Commerce Cloud: inspect the project’s .magento.app.yaml and platform scheduling. A missing traditional user crontab is not sufficient evidence of failure there. Follow Adobe’s Cloud cron guidance rather than installing a second launcher.
Layer 1 / Launch
1. Verify what actually launches Magento
whoami
pwd
command -v php
php -v
php --ini
php bin/magento --version
crontab -lOn a conventional host, compare the cron entry with your active release directory and intended PHP binary. A correct entry under another user does not prove this deployment is covered. A command copied before a release switch may still point at old code.
Inspect the operating-system scheduler using your hosting tools. On Ubuntu/Debian with systemd and sufficient access, these are useful observations:
systemctl is-active cron
journalctl -u cron --since "30 minutes ago" --no-pagerThe process-filter example later uses rg (ripgrep); use your host’s process viewer if it is unavailable. Other distributions may use crond; containers and managed hosts may use another launcher entirely. A service being active only proves the service is up. Look for attempts to execute this application’s command, then correlate those attempts with Magento evidence.
Expected: the intended scheduler repeatedly invokes the correct release, owner and PHP binary. If not: investigate a missing entry, stopped service, changed release path or incompatible CLI PHP configuration. Do not change permissions recursively to make the symptom disappear.
Layer 2 / Schedule
2. Inspect a bounded window of recent jobs
Use a time window appropriate to the task. One hour is useful for frequently scheduled work, but insufficient for a daily or weekly job. Check clock alignment before comparing application, database and host timestamps. These SQL windows assume a UTC database session; have your database operator confirm it before interpreting timestamp comparisons.
date -u
# In your database client, run the SQL below.SELECT UTC_TIMESTAMP() AS observed_utc,
@@session.time_zone AS session_time_zone;
SELECT schedule_id, job_code, status,
created_at, scheduled_at, executed_at, finished_at
FROM cron_schedule
WHERE scheduled_at >= UTC_TIMESTAMP() - INTERVAL 1 HOUR
ORDER BY scheduled_at DESC, schedule_id DESC
LIMIT 100;Then filter for the exact job you are investigating. The code below is an example for scheduled index updates; custom integrations have their own job codes.
SELECT schedule_id, job_code, status,
scheduled_at, executed_at, finished_at
FROM cron_schedule
WHERE job_code = 'indexer_update_all_views'
AND scheduled_at >= UTC_TIMESTAMP() - INTERVAL 1 HOUR
ORDER BY scheduled_at DESC, schedule_id DESC
LIMIT 30;Take a second snapshot after the relevant scheduling interval. Compare the same rows as well as new rows. A list of old successes can coexist with a current outage. Missing history can reflect cleanup, a wrong database, an incorrect job code or a task that is not due—not just a broken launcher.
Layer 3 / Execution
3. Interpret states in context
| Observation | Possible interpretation | Next evidence |
|---|---|---|
| Future pending rows | Expected scheduled work | Recheck after the due time |
| Due rows remain pending | Execution is delayed or the group is not reached | Launch history, group configuration, worker duration and clock |
| Missed | The configured start window expired | Delay and schedule_lifetime for the affected group |
| Error | An attempted task failed | Correlated exception and dependency failure |
| Running across repeated snapshots | Long work or an interrupted execution | Process, workload and database wait evidence |
| Success | This recorded task finished without a reported execution failure | The actual business outcome |
A growing count by itself is not enough. Ask which tasks are due, how old the oldest due task is, and whether the delay exceeds the normal workload for that store. Pending work scheduled for tomorrow is not today’s backlog.
For a custom job, confirm its expected frequency and group with the module maintainer. Check effective configuration rather than assuming the XML schedule is the only source.
4. Match job timestamps to errors
tail -n 100 var/log/cron.log
tail -n 100 var/log/exception.log
tail -n 100 var/log/support_report.logInspect the launcher’s redirected output too; it may be a different file, such as var/log/magento.cron.log. A PHP startup failure can happen before Magento writes its own log. Missing log files can reflect rotation or logging configuration.
Correlate one job code and one execution window. Common investigation paths include an unavailable remote API, failed database access, a missing class after a deployment, or resource exhaustion. Preserve a sanitized exception signature and timestamp before applying a fix.
If unrelated jobs continue to finish while one repeatedly errors, focus on that task first. Restarting the system scheduler may not change the task’s failing dependency.
5. Check cron groups and queue consumers separately
A launcher restricted to one group cannot establish that every group is covered. Review intended group coverage and custom module definitions. The scheduling interval and allowed start window also influence whether a delayed invocation can run due work. See Adobe’s cron-group configuration reference.
Queues introduce another boundary. The cron runner may start consumers, or the host may supervise them separately. Inspect only the relevant runner configuration locally; do not paste the complete environment configuration into a support ticket.
php bin/magento queue:consumers:list
# Linux process snapshot; inspect locally for sensitive arguments.
ps -eo pid,ppid,user,etime,args | rg "[b]in/magento (cron:run|queue:consumers:start)"The consumer list shows registrations, not throughput. An absent process can be normal for a short-lived worker, and a present process may be idle. Confirm queue age, expected messages and completed work before launching extra consumers. Refer to Adobe’s queue process-management guidance.
6. Choose the fix supported by evidence
| Evidence | Targeted response |
|---|---|
| Launcher missing on a conventional host | Back up the intended owner’s crontab; install the reviewed Magento entry |
| Wrong PHP binary or release path | Correct that entry and verify bootstrap with the intended runtime |
| One task repeatedly errors | Repair its module or dependency, then verify that task |
| Long tasks delay execution | Investigate workload, locks and capacity; consider smaller work units |
| A row appears stuck running | Establish worker/process state before any targeted recovery |
State-changing example: only after confirming the conventional-host entry is missing, back up the application owner’s crontab using the host’s normal procedure. Review and install with:
php bin/magento cron:installDo not add --force casually. Preserve existing application and custom scheduling. For a controlled manual execution, first rule out conflicting workers and identify the group. This is not a read-only health check:
php bin/magento cron:run --group="default"A manual invocation can create schedules before work becomes due. Observe the due time and the next appropriate execution; two immediate commands are not a substitute for checking timing. The group command does not select a single job code, and a completion message does not prove every business task succeeded.
Avoid blanket recovery commands: do not truncate cron history, mark every running row as success, kill all PHP processes or remove lock files indiscriminately. Those actions can destroy evidence or interrupt unrelated work. Recovery should match the affected task, host and release.
Illustrative timeline
Worked example: new rows, no completed work
This is a simulated example, not a customer incident. Assume vendor_inventory_sync is a custom job expected every five minutes.
10:00 scheduled_at=10:00 status=pending executed_at=NULL
10:06 same row status=missed executed_at=NULL
10:06 unrelated job status=success finished_at=10:05What this supports: the target did not begin within its allowed window. Another job finishing makes a total application-wide stop less likely.
What it does not establish: the cause. Investigate the target’s group, effective schedule and start window, earlier long work, and launcher coverage. Do not invent a module exception when execution never started.
After correcting the confirmed cause, the evidence you want is a newly due row with a sensible execution/finish time, followed by a successful downstream inventory update. Keep watching automatic cycles after the manual test.
Prove automatic recovery
A manual success is a useful test, but it does not establish the launcher will run unattended. Record recovery evidence that someone else can review:
- The application owner, release and PHP binary used by the scheduler are confirmed.
- New due work for the affected job is created and completed over several expected automatic cycles.
- The oldest overdue work stops aging; errors and missed jobs do not continue accumulating unexpectedly.
- The downstream result is correct: the catalog update is visible, the export arrives or a controlled email reaches its destination.
- The alert recipient and next review are assigned.
For infrequent jobs, define an observation period that includes the next due execution. An email-sent flag does not prove inbox delivery; an indexer success does not prove cache freshness. Use the wider health-check handoff checklist to record related findings.
Prevent the next silent failure
Track the age of the last relevant successful execution, overdue work and recurring task errors against a documented expected frequency. Review these checks after release-path, PHP, scheduler and module changes.
Application monitoring also has a dependency: if its own cron stops, it may stop producing fresh results or alerts. Pair internal checks with an independent heartbeat or an external review of missing observations.
Buildmerce Health Guard includes cron status monitoring, with scheduled checks and alerts described for Pro. Confirm the current product coverage and configuration; do not assume that an internal monitor independently detects its own scheduler outage.
Common questions
Why does Magento say cron ran while emails are still delayed?
The launcher or cron command can finish without proving the relevant email task ran successfully. Inspect that task, asynchronous email configuration, provider logs and inbox delivery.
Should I delete pending or missed cron rows?
Not as a first troubleshooting step. Preserve the history, identify why work is delayed and plan task-specific recovery. Removing rows does not repair a broken dependency.
Can I use the same fix on Adobe Commerce Cloud?
Cloud uses platform-managed configuration. Review its scheduling definitions and deployment procedures rather than installing an additional traditional crontab.
Is one running job proof that cron is stuck?
No. Compare duration with expected workload, active processes and repeated observations. Investigate before interrupting a worker.
Sources & revision notes
- Magento source: cron_schedule schema (development branch; compare your installed release)
- Adobe: configure and run cron jobs
- Adobe: custom cron job and group reference
- Adobe: Commerce Cloud crons property
- Adobe: manage message queues
October 27, 2026 · First edition. Documentation-reviewed commands, bounded SQL, local investigation selector and recovery criteria. Examples are illustrative; no customer logs are published.
Continue with the complete Magento 2 health check, browse all Magento guides or send a technical correction.