Skip to main content

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.phaseWhat happens
PreparingPods 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.
StoppingThe StatefulSet is scaled to 0 and SQL Server shuts down cleanly.
PausedNo pods run. status.pause.pausedAt records when the last one stopped. The Paused condition is True.
ResumingSet 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 SYNCHRONIZED right before writes stopped are then checked against the primary's hardened log, database by database; those that hold everything the primary hardened are listed with synchronized: true in status.pause.replicas. Anything it cannot verify stays false. (SQL Server 2025 with CLUSTER_TYPE = EXTERNAL refuses to demote a sole primary with SET (ROLE = SECONDARY), so ALTER AVAILABILITY GROUP ... OFFLINE is 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 Resuming and status.message names 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-2

    Only 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 MSSQLBackupSchedule skips runs that fall due while its target is paused. It records status.lastSkippedTime, emits a SkippedPaused event, sets its Available condition to reason TargetPaused, and continues from the next due time after the resume (skipped runs are not made up).
  • A MSSQLBackup or MSSQLRestore created against a paused (or pausing, or resuming) target stays Pending with reason TargetPaused and 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.