Migrate to RunxBuild and earn up to $50 in hosting credit on your first deposit.

Calculate your savings
unxBuild
Back to Blog Operations

List Cron Tasks: A Practical Guide to Every Cron Job on the Box

Sean

Platform Writer

Jun 19, 2026
7 min read

To list every cron task on a Linux box, check four places: the per-user crontab with crontab -l, the system crontab at /etc/crontab, the drop-in directory at /etc/cron.d/, and the spool at /var/spool/cron/crontabs/. Run all four. The job you forget is the one that wakes you up at 3 a.m. The reason “list cron tasks” is still a top search is that the answer has been the same for thirty years, and most tutorials cover the first of the four and call it a day.

This post covers all four, the differences between them, and the one mistake that turns a routine audit into a weekend spent reimaging a server.

List cron tasks: a practical guide to every cron job on the box

Table of contents

The direct answer: four places, four commands

# 1. The current user's crontab
crontab -l

# 2. The system crontab (different format — has a user column)
cat /etc/crontab

# 3. Drop-in jobs (one file per package or service)
ls /etc/cron.d/ && for f in /etc/cron.d/*; do echo "=== $f ==="; cat "$f"; done

# 4. The spool (per-user files written by `crontab`)
sudo ls /var/spool/cron/crontabs/

If a job is missing from all four of those, it is not a cron job — it is a systemd timer, an anacron entry, or something running under a different scheduler entirely. The audit is not done until you have ruled those out too.

The per-user crontab

The most common place for a cron task. Each user has one, and crontab -l shows the current user’s. To see another user’s, you need root:

sudo crontab -u www-data -l

The per-user crontab does not have a “user” column — the user is the user the file belongs to. The format is m h dom mon dow command. Empty lines and lines starting with # are comments. There is no MAILTO by default in most distros, so output goes to local mail, which most modern boxes do not have configured, which means the output goes nowhere and you find out a job is failing only when the consequences show up in a Slack alert two weeks later.

The trap: editing a user’s crontab installs it into the spool, not into the home directory. crontab -e writes to /var/spool/cron/crontabs/<user>, not to ~/.crontab. There is no file in the home directory to back up; the spool is the source of truth. If you back up home directories and skip the spool, you are not backing up cron.

The system crontab at /etc/crontab

The system crontab has one extra column — the user the job runs as. The format is m h dom mon dow user command. The presence of the user column is the only reliable way to tell a system crontab from a per-user one at a glance.

# /etc/crontab: system-wide crontab
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# m h dom mon dow user  command
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || run-parts --report /etc/cron.daily
47 6    * * 7   root    test -x /usr/sbin/anacron || run-parts --report /etc/cron.weekly
52 6    1 * *   root    test -x /usr/sbin/anacron || run-parts --report /etc/cron.monthly

The system crontab is the right place for jobs that have to run as root or a service user, jobs that are part of the OS, and jobs that need to be visible in source control (this file is part of the distro’s package management, so it survives upgrades). It is the wrong place for anything user-specific.

The /etc/cron.d drop-ins

Modern packages drop their cron jobs into /etc/cron.d/ instead of editing /etc/crontab. The format is the same as the system crontab (with the user column), and each file is one job or one package. The run-parts lines in /etc/crontab also walk the /etc/cron.hourly/, /etc/cron.daily/, /etc/cron.weekly/, and /etc/cron.monthly/ directories, so a job in any of those gets picked up by the schedule at the top of the system crontab.

To see all of them:

sudo run-parts --test /etc/cron.daily
sudo ls -la /etc/cron.d/ /etc/cron.daily/ /etc/cron.hourly/ /etc/cron.weekly/ /etc/cron.monthly/

The trap with the run-parts directories: filenames cannot contain a dot. A file called my-backup.sh in /etc/cron.daily/ is silently ignored. The file has to be named something like my-backup (no extension) or it will not run. This is the single most common cause of “I dropped a script in cron.daily and nothing happened.”

The spool at /var/spool/cron

The spool is where crontab -e and crontab <file> actually write. On Debian-family systems, it lives at /var/spool/cron/crontabs/; on RHEL-family systems, it is /var/spool/cron/. The files are named after the user and are owned by that user, with mode 600 (only the user can read them). The cron daemon reads them directly.

The reason the spool matters for audits: a job in the spool does not show up in ls /etc/cron* because it is not in /etc/. It also does not show up in crontab -l for any user other than the owner, unless you are root. If you are auditing a system you do not own, the spool is the place that hides the most interesting jobs.

sudo ls -la /var/spool/cron/crontabs/   # Debian/Ubuntu
sudo ls -la /var/spool/cron/            # RHEL/CentOS

What the anacron and systemd-timer cases look like

If a job is not in any of the four places above, it is probably one of:

  • An anacron job in /etc/anacrontab (for laptops and boxes that are not always on).
  • A systemd timer in /etc/systemd/system/*.timer and ~/.config/systemd/user/*.timer.
  • A at-job in the at spool, scheduled to run once at a specific time.
  • A launchd plist on macOS (different OS, different mechanism, but the same audit logic).

For systemd timers:

systemctl list-timers --all
ls /etc/systemd/system/*.timer /usr/lib/systemd/system/*.timer

The reason this matters: a server that is “migrating to systemd timers” still has cron jobs in the spool. The migration is rarely 100%. The audit has to cover both, and the only way to know which is to check both.

The audit script that catches the one you missed

The script that has saved me the most weekends:

#!/usr/bin/env bash
# audit-cron.sh — list every cron entry on the box

echo "=== Per-user crontab (current user) ==="
crontab -l 2>/dev/null || echo "(none)"

echo
echo "=== /etc/crontab (system crontab) ==="
[ -f /etc/crontab ] && cat /etc/crontab || echo "(no /etc/crontab)"

echo
echo "=== /etc/cron.d/ ==="
for f in /etc/cron.d/*; do
  [ -f "$f" ] || continue
  echo "--- $f ---"
  cat "$f"
done

echo
echo "=== /etc/cron.{hourly,daily,weekly,monthly}/ ==="
for d in /etc/cron.hourly /etc/cron.daily /etc/cron.weekly /etc/cron.monthly; do
  echo "--- $d ---"
  ls -la "$d" 2>/dev/null
done

echo
echo "=== Spool ==="
sudo ls -la /var/spool/cron/crontabs/ 2>/dev/null \
  || ls -la /var/spool/cron/ 2>/dev/null \
  || echo "(no spool access)"

echo
echo "=== systemd timers ==="
systemctl list-timers --all 2>/dev/null || echo "(systemctl unavailable)"

echo
echo "=== anacrontab ==="
[ -f /etc/anacrontab ] && cat /etc/anacrontab || echo "(no anacrontab)"

Run it with sudo so the spool is readable. Pipe the output to a file. The result is the actual state of scheduled work on the box, which is the only document you actually need when something goes sideways at 3 a.m. For a hosted box, the same audit against a managed service is a one-time job on a deploy and not worth scripting; for a fleet, the script is the difference between an audit and a prayer. The hosting calculator at runxbuild.com/pricing is the right tool to estimate what running the same audit on a managed host costs if you would rather not own the cron daemon yourself.

How this fits the rest of the stack

A cron audit script is most useful when it runs as part of a real platform, not on a developer’s laptop. The same audit shape (loop, check, report) works as a scheduled job on a managed platform: the script runs on a schedule, the output is the audit log, and the platform’s logs and retention handle the operational part. The RunxBuild hosting calculator is the right place to model what the scheduled audit job actually costs in practice — pick the runtime size, the storage for the output, the build minutes, and the cron frequency, and the calculator shows what the operational audit loop costs at the team’s actual usage.

Useful related references:

FAQ

How do I list all cron jobs for all users?

Loop over the user list and run sudo crontab -u <user> -l for each, then check /etc/crontab, /etc/cron.d/, and /var/spool/cron/. The audit script in this post does it in one run.

Where does crontab -e actually write the file?

To /var/spool/cron/crontabs/<user>, not to the home directory. There is no ~/.crontab to back up.

Why is my crontab change not taking effect?

Most often: cron is not running, the syntax has a stray character, or the file is in /etc/cron.d/ with a dotted filename (run-parts skips those).

What is the difference between /etc/crontab and /etc/cron.d/?

The system crontab is a single file with the user column. /etc/cron.d/ is a directory of drop-in files with the same format, used by packages to add their own scheduled jobs without editing the system crontab.

How do I see if a job ran and what it produced?

Check /var/log/cron (RHEL) or /var/log/syslog (Debian). The cron daemon logs every job it starts and finishes, including the exit status. For job output, configure MAILTO=your@email in the crontab or capture output to a log file with >> /var/log/myjob.log 2>&1.

Can a cron job have a different timezone?

Not in the crontab itself. Cron runs in the system timezone. To run a job in another timezone, wrap the command: TZ=America/New_York /path/to/command. The cron entry stays in system time.

#list cron tasks#crontab list#crontab -l#system crontab#cron.d#cron spool