When people talk about backup strategy, the “3-2-1 rule” comes up often: three copies of your data, on two different types of media, with one copy stored offsite. It’s a catchy sequence of numbers, but few people stop to unpack what each digit is actually protecting against. This post breaks down where the rule comes from and how it maps onto a real backup implementation.
Note: The 3-2-1 rule is widely attributed to photographer Peter Krogh. It isn’t a formal standard set by any single organization — it’s a rule of thumb that spread through practical experience.
What each number protects
The rule bundles three separate conditions:
| Number | What it means | What it protects against |
|---|---|---|
| 3 | Keep three total copies of the data (the original plus two backups) | A single corrupted backup won’t leave you with nothing to restore from |
| 2 | Store two of those copies on different types of media/storage | Failures specific to one storage medium or provider |
| 1 | Keep at least one copy in a physically separate location | Site-level events like fire, theft, or a power failure |
The key insight is that each number addresses a distinct failure mode. It’s not simply “have three backups” — the reasoning behind “why two kinds of media” and “why one offsite copy” are genuinely different arguments, worth separating.
Why isn’t “original plus one backup” enough?
Start with the simplest question: why doesn’t the original data plus a single backup (two copies total) suffice?
The answer comes from accepting that a backup itself can fail. A disk error during the backup process, a failure in the storage where the backup lives, or a corrupted file that silently gets kept as “the backup” for a long time — these are all things that actually happen. With only one backup, if that single copy happens to be bad at the moment you need it, there’s nothing left to restore from. With three total copies (original plus two backups), the failure of any one of them still leaves two intact.
Why isn’t “the same kind of storage” enough?
Next, consider the “two different media” condition. Suppose you do keep two backups, but both live on the same type of storage — say, two directories on the same server. A failure specific to that storage type (a failed storage controller, filesystem corruption, an outage at the hosting provider) can take out both backups at once, since they share the same underlying infrastructure.
Splitting backups across different media — for example, storage on a remote server versus a local disk on a separate machine, with independent hardware and independent management — means a failure in one medium is much less likely to propagate to the other.
Why isn’t “the same location” enough?
The final condition, “keep one copy offsite,” addresses a different axis entirely from media type. Even if two backups live on genuinely different storage media, if both are physically in the same building or site, a location-level event — fire, flooding, theft, a major power outage — can wipe out both regardless of how different the underlying storage technology is. Keeping a copy in a geographically separate location protects against exactly this class of event.
A real example: how this app’s backup design maps to the rule
Fully satisfying the 3-2-1 rule typically requires adding cloud storage or a dedicated offsite service into the mix. This app’s database backup design doesn’t claim to implement the full rule, but it does concretely embody the “two different media” part.
Before updating WordPress core or a plugin, the app backs up the target site’s database. It first saves the .sql file to a dedicated directory (wpmm_backups/) on the remote server, and then transfers that same file down to the maintenance operator’s local machine (Mac or Windows). In other words, the copy exists on two media with genuinely different management and hardware: server-side storage, and a disk on the operator’s own computer.
# maintenance_agent.py (simplified)
c.get(remote_backup_path, local_tmp_path)
# atomic rename after size verification
os.replace(local_tmp_path, local_backup_path)
self.manage_backup_generations(...) # local generation management
self._rotate_remote_backups(c, remote_backup_dir, site['site_name']) # remote generation management
If backups only ever lived on the server, a failure of that server itself — a disk failure, a hosting-provider incident, an accidental directory deletion — would risk losing the backups along with everything else. Keeping a second copy on the local machine gives you a copy that’s independent of whatever happens to the server. Since the operator’s machine is typically in a different physical location from the server, this design also partially edges toward the “offsite” condition, even if that isn’t its primary purpose.
Don’t confuse this “3” with the generation-count “3”
There’s a genuinely confusing coincidence worth calling out. Both the local and remote backup routines in this app use max_keep=3 — keeping only the three most recent generations of backups and deleting older ones.
def manage_backup_generations(self, safe_site_name, display_name=None, max_keep=3):
files = sorted(glob.glob(os.path.join(site_backup_dir, '*.sql')))
while len(files) > max_keep:
oldest = files.pop(0)
os.remove(oldest)
This “3” is a completely different concept from the “3” in the 3-2-1 rule. The 3-2-1 rule’s “3” is about the total number of copies that exist simultaneously, across locations and media. The generation-retention “3” is about how many points in time to keep within a single storage location — it answers “how far back can I roll back within this one backup destination,” not “how many independent copies protect me from a storage failure.” One is about redundancy against failure; the other is about how much history to retain. They happen to share a number, but conflating them leads to a misreading of what each mechanism is actually for.
Summary
| Aspect | 3-2-1 rule | This app’s generation management |
|---|---|---|
| What “3” means | Total number of copies that exist at once | Number of time-based generations kept per storage location |
| What it protects against | Backup corruption, media-specific failure, site-level disaster | The need to roll back further than “one step back” |
| Where it shows up in this app | Dual storage on server + local (media diversity) | manage_backup_generations / _rotate_remote_backups |
Having a backup isn’t the same as being protected. What matters is how many kinds of media and how many separate locations that backup actually spans. It’s a catchy mnemonic, but once you break it apart, each number turns out to correspond to a concrete, distinct failure scenario it’s meant to guard against.