Overview
You can import an existing internet-accessible MySQL database into a PlanetScale Vitess database with no downtime. An import has two parts:- An external keyspace connects your production branch to your existing MySQL database.
- A Vitess MoveTables workflow copies the tables from the external keyspace into a PlanetScale keyspace, keeps them in sync while your application keeps running, and switches traffic to PlanetScale when you’re ready.
pscale CLI. The Workflows page in the dashboard shows the progress of the import, but it is read-only: every step on this page is a CLI command.
You must be an Organization Administrator or a Database Administrator of the database to run an import. To run an import with a service token, give it the
create_branch, read_workflow, write_workflow, and delete_workflow permissions on the database, plus delete_production_branch to delete the external keyspace at the end.Import process overview
- Prepare your source database - Check its server settings, create a user for PlanetScale, and allow PlanetScale’s IP addresses
- Create your PlanetScale database - Create the Vitess database you are importing into
- Create an external keyspace - Connect the production branch to your source database. PlanetScale checks connectivity, server settings, user grants, and schema compatibility first
- Start the import - Create a MoveTables workflow from the external keyspace to your PlanetScale keyspace
- Monitor the import - Watch the copy and replication progress, then verify the data
- Connect your application to PlanetScale - Test your application against PlanetScale while your source database is still serving traffic
- Switch traffic - Move reads, then writes, to PlanetScale
- Complete the import - Stop replication and disconnect your source database
It’s recommended to avoid all schema changes / DDL (Data Definition Language) statements during an import on both your source database and the PlanetScale database. This includes
CREATE, DROP, ALTER, TRUNCATE, etc.commerce into a PlanetScale database named commerce in the acme organization.
Step 1: Prepare your source database
Server configuration
These server settings need to be set correctly for the import to work:
* Either
expire_logs_days or binlog_expire_logs_seconds needs to be set. If both are set, binlog_expire_logs_seconds takes precedence. On Amazon RDS and Aurora, set binlog retention hours to at least 48 instead. See the provider-specific migration guides for how to change these settings.
MySQL 5.6, 5.7, and 8.0 are supported. The source database must not already contain a _vt database.
Create a user for PlanetScale
PlanetScale connects to your source database with a single user. That user needs replication privileges, read and write access to the database you’re importing, and access to theps_import_* database that PlanetScale creates on your source to track replication. See Import user permissions for the full list of grants and a script that creates the user.
Allow PlanetScale’s IP addresses
Allow connections from PlanetScale’s IP addresses for your database’s region in your database firewall or security group. See Import public IP addresses for where to find them.Step 2: Create your PlanetScale database
Create the Vitess database you’re importing into:Step 3: Create an external keyspace
An external keyspace connects your production branch to your source database. It is the source of the import. Give it a name that is different from your PlanetScale keyspace, such ascommerce_source.
Connection settings
If your database server has a valid SSL certificate, set the SSL verification mode to
required or higher. For more information about certificates from a Certificate Authority, check out our Secure connections documentation.
Check your source database
Runcreate-external with --dry-run to check your source database without creating anything:
- Connectivity - It can connect with the credentials and SSL/TLS settings you provided.
- Server configuration - The server settings above are correct.
- User grants - The user has the required grants.
- Schema compatibility - Every table can be imported. See Schema compatibility below.
Schema compatibility
The check also reports tables that can’t be imported:- Missing unique key - All tables must have a unique, not-null key. See our Changing unique keys documentation for more info.
- Invalid charset - We support
utf8,utf8mb4,utf8mb3,latin1, andascii. Tables with other charsets will be flagged. - Unsupported storage engines - Only
InnoDBis supported. - Unsupported partitioning - Only
RANGEpartitioning is supported, without subpartitions.
--exclude-tables in the next step.
If your database uses foreign key constraints, PlanetScale turns on foreign key support for your PlanetScale database when you create the external keyspace. See Foreign key constraints before you start the import.
Create the external keyspace
Once the check passes, run the same command with--wait instead of --dry-run:
Step 4: Start the import
Create a MoveTables workflow that copies the tables from the external keyspace into your PlanetScale keyspace:Import options
- Tables -
--all-tablesimports every table. To import only some tables, pass--tableswith a comma-separated list instead. To import every table except a few, combine--all-tableswith--exclude-tables. - Defer secondary index creation -
--defer-secondary-keyscreates secondary (non-primary) indexes after the data is copied instead of during the copy. Maintaining many indexes while inserting data is slow, so this can make your import significantly faster (often 2-3x faster for tables with multiple indexes). Secondary indexes are created during the copy unless you pass this flag. Don’t use it if your database has foreign key constraints. - DDL handling -
--on-ddlcontrols what happens if schema changes (likeALTER TABLE,ADD INDEX, etc.) run on your source database while the import is running:STOP(default, recommended) - The workflow stops when a schema change is detected. After you review the change, restart the workflow withpscale branch vtctl move-tables start. This is the safest option because it lets you verify the schema changes won’t cause issues before continuing.IGNORE- Schema changes are skipped and won’t be applied to your PlanetScale database. Your import continues without interruption, but your schemas will diverge. Only use this if you’re confident you don’t need these changes or plan to apply them manually to your PlanetScale database later.EXEC- Schema changes are applied to your PlanetScale database while the import continues running. If applying a schema change fails (for example, if it’s not compatible with Vitess), the workflow stops and you’ll need to restart it.EXEC_IGNORE- Attempts to apply schema changes but keeps running even if they fail.
move-tables reference for every option.
Foreign key constraints
If your database uses foreign key constraints:- Import all tables - Pass
--all-tableswithout--exclude-tablesso referential integrity stays intact. - Use an atomic copy - Pass
--atomic-copy, and don’t pass--defer-secondary-keys. Foreign key constraints need their indexes to exist during the copy. - Import retries - An atomic copy holds a long-running transaction on your source database, which can increase load. If it fails, it starts over from the beginning instead of resuming where it left off.
Step 5: Monitor your import
Check the progress of the import withstatus:
table_copy_state- Rows and bytes copied so far for each table that is still copyingshard_streams- Each replication stream’s state and any error messagetraffic_state- Whether reads and writes have switched to PlanetScale
Copying while the initial data is copied, then Running once the import is replicating new changes from your source database. A Lagging stream is running but hasn’t caught up with recent changes. A Stopped or Error stream includes a message that explains why. The output also includes a next_steps field with the command to run next.
You can also follow the import in the dashboard. Click “Workflows” in the left nav, select your production branch, and open the workflow to see its streams, per-table copy progress, replication lag, and traffic routing.
To pause the import, run pscale branch vtctl move-tables stop. Run pscale branch vtctl move-tables start to resume it.
Verify data (optional)
Once the copy completes and the streams areRunning, you can verify that the data in PlanetScale matches your source database with a VDiff:
uuid. Pass it to vdiff show and repeat until the VDiff completes:
Step 6: Connect your application to PlanetScale
Once the streams areRunning, you can connect your application to PlanetScale while your source database stays the authoritative source. Until you switch traffic, PlanetScale routes queries for the imported tables to your source database through the external keyspace, so reads and writes still happen there.
Create a password for your production branch and point a test deployment of your application at PlanetScale. This is the ideal time to test your application end-to-end before switching traffic.
Step 7: Switch traffic
When you’re ready, switch traffic to PlanetScale. You can switch replica traffic first to test reads, then switch primary traffic.-
Switch replica traffic - Serve read queries sent to replicas from PlanetScale while writes still go to your source database. This is an optional intermediate step that lets you test read traffic separately.
-
Switch primary traffic - Serve both reads and writes from PlanetScale.
--dry-run to see what a switch would do without applying it.
After primary traffic switches, PlanetScale replicates writes back to your source database, so both stay in sync until you complete the import. If something goes wrong, switch traffic back to your source database:
Step 8: Complete the import
Once you’ve switched all traffic to PlanetScale and verified everything is working:1
Monitor your application for any issues. Check:
- Application logs for errors
- Replication lag (should be near zero)
- Error tracking tools
- Application performance metrics
2
Preview what completing the workflow will do:
3
When you’re confident everything is working correctly, run the same command without
--dry-run.4
Delete the external keyspace to disconnect PlanetScale from your source database:
--keep-data must be true when you complete an import. Your source database’s tables are never dropped or renamed. --keep-routing-rules=false removes the routing rules that sent queries to the external keyspace. Write both flags with an =: a space-separated value such as --keep-data false is read as --keep-data=true.
What happens when you complete:
- Replication from PlanetScale back to your source database stops
- The routing rules for the imported tables are removed
- The workflow no longer appears on the Workflows page
- PlanetScale disconnects from your source database
- The source database’s credentials are removed from PlanetScale
ps_import_* database from your source database and remove the user you created for PlanetScale.
Cancel an import
To stop an import before you complete it, cancel the workflow:--keep-data=false deletes the data already copied into your PlanetScale keyspace. The external keyspace stays connected, so you can fix the problem and start a new workflow. Delete the external keyspace if you don’t plan to try again.
Next steps
You just migrated your database to PlanetScale. Here are some things you can do next:- Create a development branch - Use branching in your development workflow.
- Create a deploy request - Test schema changes in dev branches before pushing to production.
Provider-specific migration guides
For detailed instructions on preparing your external database for import, see our provider-specific guides:- Amazon Aurora
- AWS RDS for MySQL
- Azure Database for MySQL
- DigitalOcean MySQL
- Google Cloud SQL
- MariaDB

