Pausing & Resuming
spec.paused lets you stop a MSSQLInstance or MSSQLAvailabilityGroup
without deleting it — useful for cutting cost on an environment you don't need
around the clock. Set it to true and the operator safely shuts SQL Server
down and scales the underlying StatefulSet to 0 replicas, so the compute is
released. The safe shutdown described on this page is available since
v0.1.16; earlier versions scale the StatefulSet straight to 0.
Everything else is preserved:
- PersistentVolumeClaims (your databases) — StatefulSets never delete PVCs on scale-down, so all data is retained.
- Secrets (SA password, TLS certificates), ConfigMaps (
mssql.conf, monitoring config). - Services (headless, exposed, and AG primary/replicas), so DNS names stay stable.
spec.size is not changed while paused — it is remembered so that
clearing the flag restores the previous replica count.
spec:
size: 3
paused: true # stop all pods, keep storage + config; resume later with paused: false
To start the cluster again, set paused: false (or remove the field).
Why this isn't just scale-to-zero
Stopping every replica at once and letting regular failover elect a primary afterwards can promote a replica that was behind. For a standalone instance that's not a concern, but on an Availability Group it means the resumed primary might not hold every transaction the old primary acknowledged. Pausing an AG instead stops writes before any pod terminates, and the resume promotes the specific replica the operator confirmed was caught up — never "whoever grabs the Lease first."
How a pause proceeds
Progress is recorded in status.pause and the Paused condition, and
status.state moves through Pausing → Paused → Resuming → Ready:
status.pause.phase | What happens |
|---|---|
Preparing | Pods keep running. The operator waits for running MSSQLBackup/MSSQLRestore operations against the resource to finish, then checkpoints the databases. An Availability Group also waits (up to 2 minutes) for its synchronous-commit secondaries to be SYNCHRONIZED, records the primary, stops writes by taking the AG offline on the primary, and records which replicas hold every transaction. |
Stopping | The StatefulSet is scaled to 0 and SQL Server shuts down cleanly. |
Paused | No pods run. status.pause.pausedAt records when the last one stopped. The Paused condition is True. |
Resuming | Set when paused is cleared. The StatefulSet scales back to size on the same PVCs. A standalone instance has resumed once every pod is ready; an Availability Group once its primary is back. status.pause is then removed. |
status.pause.message says what a step is waiting for, e.g. waiting for backup nightly-full to finish.
Clearing paused while still Preparing cancels the pause. Setting it again
while Resuming pauses again; an Availability Group whose primary is already
back stops writes again first.
Standalone instance
Pausing an MSSQLInstance is straightforward: wait for any running backup or
restore to finish, checkpoint the databases, scale to 0, and resume once the
pods are ready again. There's no primary to track and no eligibility check —
a single replica either comes back or it doesn't.
Availability Group: no data loss, deterministic primary
-
Writes stop before any pod does. Once the AG is offline on the primary, no replica can receive transactions the others miss. Replicas that were
SYNCHRONIZEDright before writes stopped are then checked against the primary's hardened log, database by database; those that hold everything the primary hardened are listed withsynchronized: trueinstatus.pause.replicas. Anything it cannot verify staysfalse. (SQL Server 2025 withCLUSTER_TYPE = EXTERNALrefuses to demote a sole primary withSET (ROLE = SECONDARY), soALTER AVAILABILITY GROUP ... OFFLINEis the mechanism used to stop writes.) -
The recorded primary comes back as primary. On resume the operator promotes only
status.pause.primary. Automatic failover, re-seeding and rejoin logic stay off from the moment writes stop until that replica is primary again. -
If the recorded primary cannot come back (lost node or volume), the AG waits in
Resumingandstatus.messagenames the replicas you can promote instead. Annotate the resource with one of them:kubectl annotate mssqlavailabilitygroup my-ag mssql.solanica.io/resume-primary=my-ag-2Only a replica recorded as synchronized is accepted (the webhook also rejects names that are not a replica of the AG). The operator tries a graceful failover first. It forces one only if it can reconfirm, from the current replicas, that nothing is ahead of the one being promoted. The operator removes the annotation once the resume completes.
The AG keeps running its current image while paused and resuming: an image change made meanwhile rolls out after the resume through the usual ordered upgrade (see Version, Edition & Topology Changes).
Changes while paused
Spec changes made while paused are accepted (the webhook returns a warning) and take effect when the resource resumes; the pods start directly with the new settings.
Backups and restores
Backups and restores do not run against a paused resource:
- A
MSSQLBackupScheduleskips runs that fall due while its target is paused. It recordsstatus.lastSkippedTime, emits aSkippedPausedevent, sets itsAvailablecondition to reasonTargetPaused, and continues from the next due time after the resume (skipped runs are not made up). - A
MSSQLBackuporMSSQLRestorecreated against a paused (or pausing, or resuming) target staysPendingwith reasonTargetPausedand runs once the target has resumed. - A pause waits for any backup or restore already running against the target to finish before it stops writes.
See Backups & Restores for everything else about the backup and restore CRDs.
Status fields
status:
state: Ready # Initializing | Ready | Error | Pausing | Paused | Resuming
pause: # only while paused, pausing or resuming
phase: Paused # Preparing | Stopping | Paused | Resuming
requestedAt: "2026-01-01T10:00:00Z"
pausedAt: "2026-01-01T10:00:12Z"
primary: my-mssql-1 # AG only: the primary restored on resume
replicas: # AG only: state of each replica when writes stopped
- name: my-mssql-0
availabilityMode: SYNCHRONOUS_COMMIT
synchronized: true
See CR Reference for the full spec and status field listing.