A systemd timer that runs twice after a reboot

2026-11-08 · 3 min read

A systemd timer that runs twice after a reboot

After every reboot, your 03:10 backup starts twice. Two processes race for the same lock, one exits with “another instance is running,” the timer looks healthy, and you get a pager alert plus a half-finished upload. The cause is usually not the job itself: it is two independent activation paths.

Diagnose the duplicate before editing units

First prove there are two starts, not one start and a retry:


journalctl -u backup.service --since "30 min ago" -o short-precise
systemctl list-timers --all 'backup*'
systemctl status backup.service backup.timer --no-pager

Then inspect the units and enablement:


systemctl cat backup.timer backup.service
systemctl is-enabled backup.timer backup.service
ls -l /etc/systemd/system/*.wants/backup.*

Look for two things: a service that is enabled separately from its timer, and a timer with both a calendar schedule and a boot-relative trigger. Also check for two timers that both start the same service.

Why a systemd timer persistent duplicate run happens after reboot

With Persistent=true, systemd records the last trigger and fires the timer when it becomes active if the scheduled time passed while the machine was down [link needed]. That catch-up run is intentional. A systemd timer persistent duplicate run appears when that catch-up is added to another start path.

The common case is a service with [Install] WantedBy=multi-user.target that is also enabled. At boot, systemd starts the service directly; moments later, the persistent timer catches up and starts it again. A timer with both OnCalendar= and OnBootSec= can produce the same effect, because both triggers are active. Two timers with overlapping schedules and the same Unit= are another source.

Stop the duplicate with this procedure

1. Decide which unit owns the schedule. If backup.timer has the OnCalendar= entry, the timer should start the service; the service should not also be enabled at boot.

2. Disable the service’s independent boot start, keeping the timer enabled:

```bash

sudo systemctl disable backup.service

sudo systemctl daemon-reload

sudo systemctl restart backup.timer

```

Do not mask the service unless you also intend to block timer starts.

3. If the timer itself has two triggers, remove the redundant one. For a scheduled backup, keep OnCalendar= and Persistent=true; remove OnBootSec= unless you need an additional boot-relative run.

4. If a second timer targets the same service, disable the duplicate timer:

```bash

sudo systemctl disable --now backup-extra.timer

```

5. Validate without waiting for the calendar: check systemctl list-timers --all, run systemctl start backup.service once manually, then reboot and compare journalctl timestamps. If you are testing catch-up behavior, inspect /var/lib/systemd/timers/ for the timer’s stamp file [link needed].

When NOT to do this

Do not disable the service if other units pull it in with Wants= or Requires=, or if boot-time execution is required even when the timer is inactive. Do not remove Persistent=true just to hide duplicates: that also removes catch-up after downtime. And if the service is socket-activated or started by a path unit, disabling its boot start may not remove the second path; fix the actual trigger instead.

Checklist

ad slot — paste the network tag here