Solving Cron & Scheduler issues in SuitCRM
Critical Setup Checklist
SuiteCRM actually needs two separate cron entries, not one — most guides (including SuiteCRM’s own on-screen instructions) only mention the legacy one, which silently leaves some jobs permanently broken.
Legacy cron entry — runs cron.php, handles most jobs (function::... style)
Modern console entry — runs bin/console schedulers:run, handles scheduler::... style jobs — without this, “Queue Campaign Emails” and “Send Campaign Emails” never run, ever, with no error shown anywhere
The two entries must be staggered (not fired at the exact same moment) or the second one silently throttles itself out every cycle
allowed_cron_users in config.php must list both the OS cron user and the SuiteCRM application scheduler user
Any scheduler’s date_time_start must stay at the generic 2015-01-01 value — never a real date
Configuration Steps
Step 1 — The Crontab
Why both are needed at all: SuiteCRM’s legacy cron.php scheduler-selection query contains:
Step 2 — allowed_cron_users
user1 — the Linux/OS-level cron user (matches the crontab owner)user2 — the SuiteCRM application-level scheduler username (shown in Admin → Schedulers → “Last user to run schedulers”)
These are two different types of usernames, both required in the same array. If a scheduler shows “This user is not part of allowed_cron_users config setting”, this is the fix.
No service restart needed — config.php is read fresh on each request/cron run. Run Admin → Repair → Quick Repair and Rebuild if changes don’t seem to take effect.
Step 3 — Verify It’s Actually Working
Don’t trust the Admin → Schedulers summary page alone — it can show stale/misleading “Last successful run” data. Check the database directly.
Check all schedulers’ real last-run times:
Check individual job execution history (not “schedulers_jobs” — that table doesn’t exist):
ERROR [app] Jobs run too frequently, throttled to protect the system / No Schedulers to run, you’ve just run it within 30 seconds of the last automatic cron tick — wait and try again, or check the stagger in Step 1.SuiteCRM
Common Mistakes & Symptoms
| Symptom | Cause | Fix |
|---|---|---|
“Last user to run schedulers… this user is not part of allowed_cron_users“ |
App-level scheduler user missing from config.php | Add the app-level username (e.g. user2) to allowed_cron_users alongside the OS user |
| A scheduler’s “Last Successful Run” frozen at one exact timestamp, forever, despite Active status and correct interval | date_time_start was set to a real date instead of the generic 2015-01-01 value (usually from an accidental edit via the UI’s date/time start field) |
UPDATE schedulers SET date_time_start='2015-01-01 HH:MM:01' WHERE name='...'; — match what every other scheduler uses |
“Run Nightly Mass Email Campaigns” (or similar) shows job_queue status=success repeatedly, but nothing real ever happens |
The scheduler’s own eligibility check is silently failing (e.g. a date-parsing error) before it ever reaches your actual data — success is only reported for the outer dispatch wrapper | Temporarily set config.php‘s log level to debug, force a run, grep the log for ERROR/did NOT find valid job lines, then revert log level to fatal |
“Queue Campaign Emails” / “Send Campaign Emails” show last_run frozen at one old date, forever, *::*::*::*::* interval, Active status |
Legacy cron.php structurally excludes scheduler::-prefixed jobs (see Step 1) |
Add the staggered bin/console schedulers:run crontab entry |
An Email Marketing record’s own status gets permanently stuck at active or sending, never progressing |
The run that set that status was interrupted mid-batch (e.g. crashed on an unrelated broken record elsewhere in the send queue) before it could complete or revert | Check SELECT status FROM email_marketing WHERE id='...' directly. If stuck at active/sending with no real activity, reset back to pending_send (back up the table first) and let a fresh cron cycle pick it up |
A [FATAL] Error retrieving template for the email campaign loop, same marketing_id repeating endlessly every cycle |
An old/completed Email Marketing record has a blank or invalid template_id, and its leftover emailman queue rows never got cleared — the send function hits this broken record on every pass and exits before reaching genuine new work |
Find the broken record: check its template_id. Soft-delete its stuck emailman rows: UPDATE emailman SET deleted=1 WHERE marketing_id='...'; |
Inbound mailbox (support@, bounces@) shows AUTHENTICATIONFAILED every cron cycle |
Stored password in SuiteCRM doesn’t match the actual mailbox password | Re-enter password in Admin → Inbound Email, use Test Settings before saving |
Email Reminder: error sending email, system smtp server is not set every cycle |
System-level Outbound Email account (Admin → Email Settings) never configured | Fill in real SMTP details on the “system” Outbound Email Account, enable “Users may send as this account’s identity” if needed |
Database Reference
Useful tables for diagnosing scheduler/cron issues (always DESCRIBE tablename; first — don’t guess column names):
| Table | Purpose |
|---|---|
schedulers |
Scheduler definitions: interval, status, last_run, date_time_start |
job_queue |
Individual execution attempts/results for scheduled jobs (status, resolution, execute_time) |
emailman |
Individual queued campaign emails, one row per recipient per send |
campaign_log |
Per-recipient campaign activity (targeted, sent, viewed, blocked-opted-out, blocked-duplicate-email, etc.) |
email_marketing |
One row per campaign send instance (status, template_id, date_start) |
email_marketing_prospect_lists |
Links an Email Marketing record to its Target List(s) |
prospect_list_campaigns |
Links a Target List to a Campaign |
prospect_lists_prospects |
Actual membership of a Target List (related_id, related_type) |
