Cron Jobs on Shared Hosting: Common Pitfalls

Cron on shared hosting sounds simple. Run a script on a schedule. Back up the site. Sync inventory. Kick WordPress scheduled tasks. In practice, cron is where a lot of quiet sites quietly break themselves.

The front end still loads. Google Analytics looks fine. Then backups stop running, orders stop syncing, or the host sends a warning about CPU abuse. Nobody touched the homepage. Someone (or some plugin) set up a cron job wrong months ago.

Wrong PHP path or working directory

cPanel cron forms love to suggest /usr/bin/php. Your account might need /usr/local/bin/php or a versioned binary like ea-php81. Run which php over SSH or ask support which binary matches your site. Guessing is how you get empty log files and jobs that never ran.

Working directory matters too. A script that does require 'wp-load.php' only works if cron starts in the WordPress root. Set cd /home/you/public_html && before the command, or use absolute paths everywhere.

wp-cron vs a real system cron

WordPress ships with pseudo-cron: scheduled tasks fire when someone visits the site. Low-traffic sites miss tasks. High-traffic sites can trigger overlapping runs. Most production WordPress setups disable wp-cron in wp-config.php and hit wp-cron.php from a real cron entry every five or fifteen minutes.

Common mistake: disabling wp-cron but forgetting to add the system cron. Scheduled posts never publish. Subscription renewals stall. Backup plugins show "last run: never" while the dashboard still looks healthy.

Running too often

Every minute is almost never the right interval on shared hosting. Import plugins, feed syncs, and "health check" crons love to default to aggressive schedules. Five accounts on the same node all running per-minute PHP scripts is how you hit entry process limits with ten visitors a day.

Ask what the job actually needs. Daily backups do not need hourly triggers. WooCommerce Action Scheduler can usually run every five to fifteen minutes, not every sixty seconds. If a vendor plugin defaults to * * * * *, change it unless you have a very good reason.

Overlapping runs with no lock

A slow backup or import can still be running when the next cron fires. Two copies fight over the same files, database tables lock, and disk I/O spikes. Use flock or plugin-level locking:

*/15 * * * * flock -n /tmp/mybackup.lock /usr/local/bin/php /home/you/backup.php

WordPress backup plugins often have a "only one backup at a time" setting. Turn it on. Seriously.

Silent failures

Cron emails output to the account mailbox by default. Many people never read that mailbox. Jobs fail with "permission denied" for months.

Redirect output somewhere you check:

0 2 * * * /usr/local/bin/php /home/you/scripts/nightly.php >> /home/you/logs/cron-nightly.log 2>&1

Then actually look at the log after deploy week. One line of "could not connect to database" saves a weekend of mystery.

curl and wget to trigger URLs

Some hosts only let you cron HTTP requests: curl -s https://yoursite.ca/wp-cron.php?doing_wp_cron. That works if the URL is correct, HTTPS validates, and you are not caching the response at the edge. A CDN caching wp-cron means scheduled tasks never run.

Worse: a public cron URL with a predictable token becomes a denial-of-wallet button. Anyone who finds it can hammer your server. Prefer CLI (wp cron event run --due-now if WP-CLI is available) or restrict the endpoint.

Environment and memory limits

Cron runs with a minimal environment. No fancy shell profile. php might not be on PATH unless you spell it out. Memory limits can differ from web requests. A script that works in the browser can die in cron with a fatal error on line 1.

For WordPress tasks, match the PHP version the site uses on the web. Running a PHP 7.4 binary against a site that expects 8.1 is a special kind of Tuesday.

Timezone surprises

Server cron uses the server timezone unless you set CRON_TZ or schedule around UTC. Your "2 AM Edmonton backup" might be firing at 9 PM local if nobody checked date on the box. Document what timezone the panel uses and test once after daylight saving changes.

What hosts do when cron misbehaves

Shared hosts watch CPU and process counts. A runaway cron looks like abuse even when you are the victim of a plugin default. You may get throttled, suspended, or asked to move to VPS. Fixing the schedule is faster than arguing about fair use.

If you need long-running workers, queues, or jobs every few seconds, shared cron is the wrong tool. That is a signal to look at a VPS or managed environment where you control systemd, supervisors, or real job queues.

A sane checklist before you add another cron line

  • Correct PHP binary and working directory
  • Interval matches real need (not "every minute because the UI allowed it")
  • Locking so jobs cannot stack
  • Logging to a file you read
  • wp-cron disabled only if system cron replaces it
  • Test run from SSH before you trust the panel

Related read: shared hosting limits you hit before traffic does. Cron problems often show up there first.

Bottom line

Cron on shared hosting is not set-and-forget. Wrong paths, aggressive schedules, and overlapping jobs cause more outages than most theme updates. Treat cron like production code: log it, lock it, and run it only as often as the business actually needs.

Stuck debugging a cron that worked until it did not? Talk with Swift Host. We can read your crontab and plugin schedules with you and tell you what to throttle before the host does it for you.

Tags:
  • Cron
  • Shared Hosting
  • PHP
  • WordPress
  • Canadian Hosting

Need Help With Your Hosting?

Tell us about your application — we respond within 1 hour with honest recommendations.