# Cross-Project Cloud SQL Migration Using Google Database Migration Service (DMS)

* * *

Migrating a **Cloud SQL** database from one Google Cloud project to another can be challenging—especially when you want **minimal downtime** and **continuous replication** (via Change Data Capture — CDC).

Google's **Database Migration Service (DMS)** makes this straightforward, even over **public IP** connectivity (ideal when VPC peering or Shared VPC isn't feasible).

In this guide, I walk you through a real-world **cross-project** migration of a **Cloud SQL for MySQL** instance using **public IP allowlist** connectivity — **continuous mode** — from source project → destination project.

This method helped me consolidate databases, refactor environments, and improve project isolation/security/governance.

![](https://cdn.hashnode.com/uploads/covers/69b00c50abc0d950015d60e7/bf61277b-4d17-4734-b04b-fa1d5b2f384f.png align="center")

*High-level flow of DMS continuous migration with public IP connectivity*

## 1\. Introduction

### Purpose

This post provides a detailed, production-tested step-by-step guide to migrate a **Cloud SQL** instance between GCP projects using **DMS** over public IP. It covers prerequisites, IAM roles, connectivity setup, job configuration, testing, cutover (promotion), and verification.

### Target Audience

*   DevOps Engineers & SREs
    
*   Cloud Infrastructure / Database Administrators
    
*   GCP Architects performing project consolidations or refactoring
    

## 2\. Overview

**Database Migration Service (DMS)** is a fully managed GCP service for **zero/minimal-downtime** migrations to **Cloud SQL** (MySQL, PostgreSQL) and AlloyDB.

**Use cases for cross-project migration**:

*   Consolidating scattered databases into a central project
    
*   Refactoring legacy/multi-project environments
    
*   Enforcing better security & governance through project boundaries
    

We use **continuous migration** (full load + CDC) over **public IP allowlist** connectivity.

**Note**: All DMS resources (connection profile, migration job, etc.) **must reside in the same region** as the destination Cloud SQL instance.

## 3\. Prerequisites

### Tools & Versions

| Tool / Technology | Requirement |
| --- | --- |
| Google Cloud Platform | Active billing in **both** projects |
| Cloud SQL | Same engine & version (e.g. MySQL 8.0.35+) |
| Database Migration Service | Enabled in the **destination** project |

### Required IAM Roles

| Role | Project | Purpose |
| --- | --- | --- |
| Cloud SQL Admin (`roles/cloudsql.admin`) | Both | Manage Cloud SQL instances |
| Database Migration Admin (`roles/datamigration.admin`) | Destination | Create & manage DMS jobs/profiles |
| Compute Network Admin (`roles/compute.networkAdmin`) | Destination | Manage authorized networks (allowlist) |

## 4\. Step-by-Step Migration Guide

### Step 1: Get the Public IP of the Source Cloud SQL Instance

*   Go to **SQL > Instances** in the **source** project
    
*   Open the instance → **Overview** tab
    
*   Copy the **Public IP address**
    

![](https://cdn.hashnode.com/uploads/covers/69b00c50abc0d950015d60e7/f63afd96-d9f7-4c46-8eb8-493198bdf48a.png align="center")

### Step 2: Create a Connection Profile in the Destination Project

*   Navigate to **Database Migration > Connection profiles > Create profile**
    
*   Settings:
    
    *   **Profile role**: Source
        
    *   **Database engine**: MySQL (or PostgreSQL)
        
    *   **Connection profile name/ID**: e.g. `source-db-profile`
        
    *   **Hostname/IP**: Paste source Cloud SQL **public IP**
        
    *   **Port**: 3306 (MySQL) or 5432 (PostgreSQL)
        
    *   **Username/Password**: Source DB credentials (e.g. `root` user)
        
    *   **Region**: Must match destination Cloud SQL region
        
*   Save
    

![](https://cdn.hashnode.com/uploads/covers/69b00c50abc0d950015d60e7/be2dcf92-f5dc-46d6-ada1-58ddbcd78fcf.png align="center")

### Step 3: Create the Migration Job

*   Go to **Database Migration > Migration jobs > Create**
    
*   Fill basics:
    
    *   **Migration job name/ID**: e.g. `cross-project-mig`
        
    *   **Source database engine**: MySQL
        
    *   **Destination region**: (same as target instance)
        
    *   **Migration job type**: **Continuous** (enables CDC / real-time sync)
        

![](https://cdn.hashnode.com/uploads/covers/69b00c50abc0d950015d60e7/5ff89511-ee94-4ee4-aa38-9b1bed17e837.png align="center")

### Step 4: Define Source Configuration

*   Select the connection profile created in Step 2
    
*   **Full dump configuration**:
    
    *   Dump method: **Logical**
        
    *   Parallelism: **Optimal** or **Max** (for better performance)
        

![](https://cdn.hashnode.com/uploads/covers/69b00c50abc0d950015d60e7/bd562775-df49-4674-8f00-75776ea36221.png align="center")

### Step 5: Define the Destination Cloud SQL Instance

*   **Option A** — Existing instance: Select it (must match engine/version)
    
*   **Option B** — New instance: Let DMS create it
    
    *   Match source engine & version
        
    *   Set root password
        
    *   Choose adequate machine type & storage (under-provisioning slows migration!)
        

**Important**: This choice (existing vs new) is **permanent**.

![](https://cdn.hashnode.com/uploads/covers/69b00c50abc0d950015d60e7/ea40fbc5-e0c5-4980-beb2-ada1755be0ba.png align="center")

![](https://cdn.hashnode.com/uploads/covers/69b00c50abc0d950015d60e7/25f3715d-7ede-439b-9382-64bc68deee06.png align="center")

### Step 6: Configure IP Allowlist (Public Connectivity)

DMS requires bidirectional connectivity over public IP.

1.  **Destination instance**:
    
    *   Go to **Cloud SQL > Connections**
        
    *   Enable **Public IP** if not already
        
    *   Note the **Outgoing IP** from Overview tab (this is the IP DMS uses to connect **to source**)
        
2.  **Source instance**:
    
    *   Go to **Cloud SQL > Connections > Authorized networks**
        
    *   Add the **destination's outgoing IP** (from step above) as an authorized network
        

![](https://cdn.hashnode.com/uploads/covers/69b00c50abc0d950015d60e7/daba0747-4483-4a65-b565-72abbe51cac6.png align="center")

![](https://cdn.hashnode.com/uploads/covers/69b00c50abc0d950015d60e7/c83dd31c-f6ad-4158-b267-771dc3ca5f51.png align="center")

### Step 7: Test the Migration Job

*   In the migration job creation wizard → **Test** button
    
*   Wait for "Test run complete – successful"
    
*   If it fails: double-check credentials, public IPs, allowlist, firewall rules
    

Once passed → **Create** (you can start immediately or later)

![](https://cdn.hashnode.com/uploads/covers/69b00c50abc0d950015d60e7/7caafd02-bfe0-4294-abe8-1dbe0f216456.png align="center")

![](https://cdn.hashnode.com/uploads/covers/69b00c50abc0d950015d60e7/e986437a-3590-4f87-bf49-a2a8b220b98a.png align="center")

### Step 8: Start & Monitor the Job and Verify Data Consistency

*   Start the job
    
*   Monitor:
    
    *   Replication delay / lag
        
    *   Phase (Full catch-up → CDC)
        

Source :

![](https://cdn.hashnode.com/uploads/covers/69b00c50abc0d950015d60e7/cf28bddc-a461-4efa-99d7-6c56deed408d.png align="center")

![](https://cdn.hashnode.com/uploads/covers/69b00c50abc0d950015d60e7/ec6c025b-946f-49d0-8865-988c2d4acc14.png align="center")

Destination :

![](https://cdn.hashnode.com/uploads/covers/69b00c50abc0d950015d60e7/4e42df5f-612c-47a7-aaee-e5dff7546474.png align="center")

![](https://cdn.hashnode.com/uploads/covers/69b00c50abc0d950015d60e7/200de87b-f70e-4cec-a1dd-967d6435ce08.png align="center")

### Step 9: Promote the Destination instance

After the verification of data consistency, Once the replication delay is least, proceed with promoting the destination Database to be a writeable instance.

![](https://cdn.hashnode.com/uploads/covers/69b00c50abc0d950015d60e7/ef3d3635-a306-47c4-bdae-7a4f1f32a0a3.png align="center")

### Step 10: Check Migration Job Logs or Destination Instance Logs

If the logs for the migration job or the destination instance logs are required, they can be viewed by clicking on the view logs and selecting the logs which are required.

![](https://cdn.hashnode.com/uploads/covers/69b00c50abc0d950015d60e7/0f0c01af-edee-43e3-b7f9-727fee59578f.png align="center")

## 5\. Troubleshooting

### 5.1 : Common Issues

| Issues | Possible Cause |
| --- | --- |
| Connection Test Fails | Public IP not whitelisted or wrong Credentials |
| Version Mismatch | Cloud SQL minor version mismatch |
| IAM Permission errors | Missing roles in source/destination |
| Cutover Fails | Replication lag or write operations on source. |

### 5.2 : Solutions

*   Re-check authorized network setting
    
*   Verify SQL Version via gcloud sql instance describe
    
*   Ensure IAM Roles and API's are correctly configured
    

## 6\. Conclusion

This blog explained how to migrate a Cloud SQL instance across GCP Projects using DMS over public IP.

It covered :

1.  API Setup
    
2.  Source/Destination Configuration
    
3.  DMS Connection profiles and job creation
    
4.  Troubleshooting the issues
