[email protected]

Migrate Cloud SQL to PostgreSQL on Hetzner

Migrate Cloud SQL to PostgreSQL on Hetzner

Editorial note: The information in this article was compiled to the best of our knowledge at the time of publication. Technical details, prices, versions, licensing terms, and external content may change. Please verify the information provided independently, particularly before making business-critical or security-related decisions. This article does not replace individual professional, legal, or tax advice.

Moving Cloud SQL out of Google Cloud? WZ-IT supports Google Cloud migration to Hetzner with target architecture, data transfer and a cutover plan. Book an initial consultation

A Cloud SQL database is only part of a migration. Logins, extensions, applications and subsequent operations must also fit. This guide covers Cloud SQL for PostgreSQL to self-operated PostgreSQL on a Hetzner VM, with a planned write freeze. It is not a MySQL guide and does not describe a test carried out on a customer environment.

As of 19 October 2026. Commands are Bash templates. Replace hosts, roles, database names, certificates and paths before rehearsal. We recommend an isolated restore first, followed by a production procedure with documented acceptance criteria.

Table of contents

Which migration method fits?

Google documents exporting Cloud SQL with pg_dump. A dump exports a database, not an entire Google project. We recommend the following distinctions:

Condition Approach Clarify first
Write freeze for transfer and acceptance is acceptable Dump and restore as described here Rehearsal, data volume, maintenance approval
Applications must write during initial transfer Separate logical replication plan Source configuration, network, tables and catch-up
Other services remain on Google Cloud Partial migration Latency, connectivity, identities and traffic

Logical replication is not a complete database clone: DDL and sequence values are not replicated automatically; large objects are also excluded (PostgreSQL logical replication restrictions). Cloud SQL configuration therefore belongs in a separate plan. This procedure does not configure replication.

For the target decision, we recommend assigning responsibility for updates, backups, recovery, monitoring and incidents before moving. Ordering a VM does not replace this operational plan. The Cloud Exit Check assesses these dependencies before a migration is commissioned.

Check versions, roles and extensions

Collect at least the following from the source:

SHOW server_version;
SELECT current_database(), pg_size_pretty(pg_database_size(current_database()));
SELECT extname, extversion FROM pg_extension ORDER BY extname;
SELECT schemaname, tablename, policyname, roles FROM pg_policies;
SELECT datname, pg_encoding_to_char(encoding), datcollate, datctype
FROM pg_database WHERE datname = current_database();

The major version of pg_dump must not be older than the source server major version. Dumps are intended for transfer to newer versions; a downgrade is not guaranteed (pg_dump compatibility). For this procedure, we recommend the same supported major version on the target; an upgrade can be planned separately. Use pg_dump and pg_restore from the same installation of that major version. A newer pg_dump does not guarantee SQL compatible with an older target server, even when its major version matches the source.

Inventory Target decision
Extensions and versions Check available packages and upgrade paths
Owners, login roles, memberships Create an explicit application role model
Row-level security and SECURITY DEFINER Accept ownership and permissions through application tests
Databases and connections Record each database plus FDW and dblink destinations
Encoding and collation Check target settings and possible sorting differences

Cloud SQL supports a defined extension catalogue. Availability there does not establish that the same extension and version are installed on the Hetzner VM. We recommend preparing required packages and preload settings before restore and documenting the result in rehearsal.

The Cloud SQL administrator does not have unrestricted PostgreSQL superuser privileges; Cloud SQL roles and IAM logins are not recreated automatically on the target. An individual pg_dump does not include cluster-wide roles (SQL dump). Do not blindly import a global role export containing Google-internal accounts.

Prepare source access and target

The example uses Cloud SQL Auth Proxy v2 on the migration machine, bound to loopback. Prerequisites include an installed proxy, enabled Cloud SQL Admin API, suitable Google credentials and the IAM permission to connect. For a private-IP-only instance, the machine also needs a network path to the VPC; the proxy does not establish that path (proxy configuration).

cloud-sql-proxy --address 127.0.0.1 --port 55432 PROJECT:REGION:INSTANCE

For a connection through the private IP, add --private-ip to the proxy command; a network path to the VPC is still required (use private IP). Keep the proxy running in a separate terminal. This example uses a regular PostgreSQL password login. Store the password in .pgpass or an approved secret mechanism, not in the shell command. On Unix the password file must have restrictive permissions, such as chmod 600 ~/.pgpass (password file).

Define connections without passwords in the Bash session:

export SRC_DSN='host=127.0.0.1 port=55432 dbname=appdb user=export_user sslmode=disable'
export DST_ADMIN='host=db.internal.example dbname=postgres user=migration_admin sslmode=verify-full sslrootcert=/secure/target-ca.pem'
export DST_DSN='host=db.internal.example dbname=appdb_migration user=migration_admin sslmode=verify-full sslrootcert=/secure/target-ca.pem'

Here sslmode=disable applies only to the local hop to the proxy; its Cloud SQL connection is TLS-protected. The target example assumes a reachable private host with a valid certificate, matching DNS name and prepared administrative privileges. Do not expose PostgreSQL generally to the internet for this guide.

Create a dedicated owner role and a new, empty database on the target. app_owner deliberately has no login. migration_admin must be allowed to assume that role. Decide encoding and locale beforehand; template0 provides the basis for an empty database.

psql "$DST_ADMIN" -X -v ON_ERROR_STOP=1   -c 'CREATE ROLE app_owner NOLOGIN;'
createdb --maintenance-db="$DST_ADMIN"   --template=template0 --owner=app_owner appdb_migration

Create the role only once; if it exists, inspect its attributes. Use another empty database for a repeated rehearsal. Consolidating ownership as shown is suitable only if multiple original owners can legitimately map to one role. Otherwise, prepare a detailed role mapping first.

Before restore, inventory all roles referenced in the dump definitions and create them on the target according to the role plan. The pg_policies query above identifies the target roles of RLS policies; also inspect the archive schema output using pg_restore --schema-only --no-owner --no-privileges --file=cloudsql-schema.sql cloudsql-final.dump once the dump is available. For example, CREATE POLICY ... TO app_reader requires an existing app_reader role during restore (CREATE POLICY). Keep logins that are not yet needed disabled with NOLOGIN. --no-privileges suppresses GRANT/REVOKE, not policy definitions (pg_restore). Configure credentials and additional permissions after restore.

Create and restore the final dump

Before the final dump, we recommend a documented gate: stop web applications, workers, cron jobs, imports and administrative access; inspect open write transactions; freeze schema changes. A read-only banner alone does not establish that every process has stopped writing.

pg_dump produces a consistent snapshot even during concurrent operation. That snapshot does not contain later changes (pg_dump). In this procedure the source therefore remains without writes from the final dump until target approval.

umask 077
pg_dump --dbname="$SRC_DSN" --format=custom   --file=cloudsql-final.dump
pg_restore --list cloudsql-final.dump > cloudsql-final.toc

Check exit status and error messages after every command. Do not continue without a successful dump. The export user needs access to all objects being backed up. Review RLS in particular: a restricted export must not silently capture only a subset of business data (row security).

Read the custom archive with pg_restore. This example deliberately does not restore original ownership and ACLs, leaving them to the prepared role model. --exit-on-error stops at the first SQL error (pg_restore options):

pg_restore --dbname="$DST_DSN" --role=app_owner   --no-owner --no-privileges --exit-on-error   cloudsql-final.dump

There is no --clean against an existing production database here. A failed restore is not an approved partial database. Fix the error and restart on a new empty target. If an extension requires privileged installation, an administrator must prepare it appropriately; do not bypass missing objects by commenting them out indiscriminately.

The archive contains application data. For transfer and storage, we recommend encrypted connections, restricted access, an integrity check after transfer and a defined deletion deadline. The examples run dump and restore from the same migration machine, requiring no additional file transfer.

Check data and application permissions

After restore, add new credentials, required memberships, database and schema permissions, and default privileges to the application roles already created. Permissions omitted using --no-privileges must be replaced deliberately. In particular, the application should not permanently run as administrator merely for migration convenience.

For acceptance, we recommend a recorded checklist:

Check Acceptance criterion
Tables and data Expected tables, exact row counts for selected critical tables and business totals agree while the source is frozen
Constraints, indexes and extensions Expected objects present, no unresolved restore errors
Sequences and write tests New records in isolated testing cause no key conflicts
Permissions and RLS Application sees and changes only intended data
Application and integrations Reads, writes, background jobs and external connections checked
Operations Target backup, restore and alert paths checked

Rebuild optimizer statistics after restoration (PostgreSQL SQL dump restoration). Run analysis explicitly as app_owner: permission to use SET ROLE does not automatically imply privilege inheritance (role membership). Example after restore:

psql "$DST_DSN" -X -v ON_ERROR_STOP=1 \
  -c 'SET ROLE app_owner;' \
  -c 'ANALYZE VERBOSE;'

SET ROLE and ANALYZE run in the same psql session (SET ROLE). ANALYZE VERBOSE builds statistics and reports the tables processed; inspect output and warnings for skipped application tables and resolve missing permissions before acceptance (ANALYZE). Database size alone does not prove data equivalence. Rehearsal write tests belong on an isolated test target. The final target must accept production changes only after approval.

Define cutover and rollback

We recommend deciding in advance who approves the cutover and which findings trigger an abort. For this dump procedure:

  1. Stop all writers and inspect the source.
  2. Create the final dump, restore into an empty target and accept the data.
  3. Switch application connection settings and secrets to the target.
  4. Run controlled checks first; explicitly approve writes.
  5. Activate workers and jobs in order; observe errors, connections and database load.

Rollback before write approval: If the source is unchanged and the target has accepted no new production data, applications can return to the source after checks.

Rollback after write approval: Changing the address alone would hide new target data. Stop writers again and decide how to transfer data back or reconcile it. Plan that return path before cutover. Do not promise an automatic lossless rollback.

We recommend retaining the old instance, protected against writes, until documented acceptance. Cancellation and deletion are a separate step after acceptance, with retention and backup requirements clarified.

Our approach at WZ-IT

Google Cloud migration to Hetzner assesses Cloud SQL together with the surrounding services. We clarify target architecture, data transfer, tests and cutover. The database focus is PostgreSQL; optional ongoing operations are scoped through Managed Operations. Scope and responsibilities are defined for the specific environment.

Further guides

Plan Cloud SQL transfer and target operations. Discuss the database, connected applications and cutover conditions for your GCP migration. Book an initial consultation

Sources

Timo Wevelsiep

Written by

Timo Wevelsiep

Co-Founder & CEO

Co-Founder of WZ-IT. Specialized in cloud infrastructure, open-source platforms and managed services for SMEs and enterprise clients worldwide.

Frequently Asked Questions

Answers to important questions about this topic

Companies worldwide trust WZ-IT

  • Stadtwerke Brühl
  • DGHO e.V.
  • solarwerkstatt berlin
  • Krüger Dirndl
  • ABCO Water Systems
  • Golem.de
  • EVADXB
  • nextGYM
  • AInergy
  • ml&s
  • Odiseo Solutions
  • Annota
  • ARGE
  • SweetConnect GmbH
  • Aphy AG
  • CORGOS
  • Rekorder
  • SolidProof
  • Yonju
  • Keymate
  • Paritel
  • Mr. Clipart
  • Millenium
  • Negosh
  • Führerscheinmacher
  • BTI
  • Deutsche Gesellschaft für Datenschutz
Read client reviews

Enquiry

Assess your Cloud SQL migration

WZ-IT assesses Cloud SQL dependencies and plans the PostgreSQL target as part of a Google Cloud migration to Hetzner.

  • Straight with Timo and Robin - no sales team, no pitch
  • A professional assessment of your situation
  • Concrete next steps for infrastructure, software or AI

The conversation is free and non-binding.

WZ-IT's advice on our Azure migration was technically sound and completely non-binding right from the intro call - we took away a great deal.
Jakob ÖschlbergerInno7 GmbH
Timo and Robin, founders of WZ-IT

Which step are you considering?

WZ-IT's advice on our Azure migration was technically sound and completely non-binding right from the intro call - we took away a great deal.
Jakob ÖschlbergerInno7 GmbH