Backup and Restore (Cloud SQL) #
Admin only. Needs
gcloud sqlwrite access and a database login. Both sit with the GCP admins. If you have lost data, post in#back-endwith the table, the rows, and the approximate time it happened.
Cloud SQL has no table-level restore. You clone the whole instance to a point in time, then copy out just what you need. Budget 1 to 2 hours — the clone alone takes 15 to 40 minutes depending on instance size.
GCP equivalent of the Aurora table recovery runbook.
Before you start: check backups actually exist #
| Staging (app DB) | Production (app DB) | |
|---|---|---|
| Terraform config | backups off, PITR off, 7 retained | backups on, PITR 35 days, 36 retained |
| Live right now | off | off |
gcloud sql instances describe funnelstory-production \
--project=funnelstory-infra-production \
--format='value(settings.backupConfiguration)'
Production backups and PITR are off, and that blocks go-live. Demoting the production instance for the migration silently turned both off.
Existing backups were kept; new ones stopped.
Terraform will not fix it — the Cloud SQL module has ignore_changes on backup_configuration.
Re-enable after promote. This command fails while the instance is still a read replica:
gcloud sql instances patch funnelstory-production --project=funnelstory-infra-production \
--backup-start-time=10:00 --enable-point-in-time-recovery --retained-transaction-log-days=35
Phase 1: clone the instance #
-
Clone to a point in time. Drop
--point-in-timeto clone the latest state:gcloud sql instances clone funnelstory-production restore-<date> \ --project=funnelstory-infra-production \ --point-in-time='2026-08-01T12:00:00Z' -
Wait for
RUNNABLE:gcloud sql instances describe restore-<date> \ --project=funnelstory-infra-production --format='value(state)' -
Connect to the clone and confirm the data is there. See psql to Cloud SQL for reaching a private-IP instance.
Phase 2: extract and restore #
-
Count first, then stage the rows:
SELECT count(*) FROM <table> WHERE <conditions>; CREATE TABLE back AS SELECT * FROM <table> WHERE <conditions>; -
Export. Small dataset → a SQL script of
INSERT/UPSERT, checked into the incident artifacts. Large dataset →COPY back TO STDOUTas CSV. -
Restore into production, dry-run first:
BEGIN; \i /path/to/restore.sql ROLLBACK; -- confirm no errors, then re-run with COMMIT -
Validate row counts and spot-check, then drop the staging table.
-
Delete the clone — it bills as a full instance:
gcloud sql instances delete restore-<date> --project=funnelstory-infra-production
Untested #
This procedure has not been run against Cloud SQL. It follows the same shape as the AWS Aurora runbook, which is proven, but the Cloud SQL version is not.
Next: do a dry run on staging before you need this for real on production.