2026-04-28·12 min read·

PlanetScale EU Alternative 2026: GDPR, CLOUD Act, and the Serverless MySQL Jurisdiction Problem

Post #678 in the sota.io EU Compliance Series

PlanetScale is the most popular managed MySQL platform for developers building production-grade applications. Its Vitess-powered architecture enables non-blocking schema changes, database branching that mirrors Git workflows, and horizontal sharding without application-level rewrites. For teams running MySQL workloads, PlanetScale became the default choice the same way Neon did for Postgres teams.

PlanetScale has a Frankfurt region. It runs on AWS eu-central-1. It provides a Data Processing Agreement.

The problem is structural: PlanetScale Inc. is incorporated in Delaware and headquartered in San Mateo, California. The CLOUD Act (18 U.S.C. § 2713) applies to every US-incorporated company and every US-controlled company, regardless of where their servers are. A valid US government order — requiring no judicial review in a European court — can compel PlanetScale to produce Frankfurt-stored database rows, branch snapshots, query logs, and schema history.

The same analysis that applies to Neon, Vercel, Supabase, and Firebase applies here. An EU region offered by a US entity does not solve the jurisdiction problem — it is a geographic description of a server rack, not a legal description of who controls the data.

This post analyses PlanetScale's GDPR and CLOUD Act exposure in detail, maps each product feature to its legal risk, and provides a complete guide to EU-native MySQL alternatives for 2026.

What PlanetScale Actually Is

PlanetScale is a managed database platform built on Vitess, the open-source MySQL clustering system originally developed at Google to scale YouTube's database infrastructure. Vitess was open-sourced in 2012 and donated to the CNCF in 2018. PlanetScale commercialised it and added developer-focused features: a branching model, a web-based schema editor, and deep analytics.

ComponentTechnologyDescription
Database EngineVitess (MySQL 8.0 compatible)Sharded MySQL with connection pooling
BranchingPlanetScale BranchesCopy-on-write schema snapshots
Schema ChangesOnline DDL / Shadow TablesNon-blocking ALTER TABLE operations
Connection PoolerVitess VTGateQuery routing and connection management
InsightsPlanetScale InsightsQuery analysis, slow query detection
Global ReplicasRead-only replicasMulti-region read distribution
BoostPlanetScale BoostQuery caching layer

Vitess's core innovation is VTGate (query router) and VTTablet (per-MySQL-instance agent). PlanetScale's managed version abstracts the entire cluster behind a MySQL-compatible connection string. From a developer perspective, it behaves like a standard MySQL database — until you need to analyse the legal jurisdiction of the infrastructure.

The CLOUD Act Problem with PlanetScale

The CLOUD Act (Clarifying Lawful Overseas Use of Data Act, 2018) amended the Stored Communications Act to explicitly state that US providers must comply with US government demands for data stored anywhere in the world. The relevant provision (18 U.S.C. § 2713) reads:

"A provider of electronic communication service or remote computing service shall comply with the obligations of this chapter to preserve, backup, or disclose the contents of a wire or electronic communication and any record or other information pertaining to a customer or subscriber within such provider's control, regardless of whether such communication, record, or other information is located within or outside of the United States."

PlanetScale falls squarely within this definition. It is:

The EU Standard Contractual Clauses (SCCs) in PlanetScale's DPA do not resolve this. SCCs are contractual instruments that establish data transfer mechanisms under GDPR Art. 46 — they do not modify US law, remove CLOUD Act obligations, or prevent US government orders. The European Court of Justice acknowledged this gap in Schrems II (C-311/18, 2020), noting that SCCs cannot protect against surveillance laws that override contractual commitments.

PlanetScale Service-by-Service GDPR Analysis

ServiceCLOUD Act RiskGDPR Art.Notes
Production DatabaseCRITICALArt. 44-49Primary data store — full exposure
Database BranchesHIGHArt. 5(1)(e)Branch = full data copy, CLOUD Act scope includes all branches
Schema HistoryMEDIUMArt. 30DDL logs reveal table structure, column names, business logic
PlanetScale InsightsHIGHArt. 25, 35Query analysis stores query patterns, slow query text (may include data)
Global ReplicasCRITICALArt. 44-49Each replica region = additional exposure point
Boost (Query Cache)HIGHArt. 5(1)(b)Cached query results may contain personal data
Audit LogsHIGHArt. 30Connection logs, query metadata — accessible to PlanetScale
Web ConsoleMEDIUMArt. 28PlanetScale employees can access console data

Database Branches: The Hidden CLOUD Act Surface

PlanetScale's branching model is its most distinctive feature and its most under-examined compliance risk. A branch in PlanetScale is:

  1. A copy-on-write snapshot of the database schema (development branches)
  2. For production deployments, the deploy request process creates a complete schema-validated replica

What this means in practice: if your production database contains personal data, and you create a development branch to test a schema migration, that branch contains a copy of your production schema — and depending on how seeding is handled, potentially a copy of your production data.

Under CLOUD Act compulsion, a US government request could demand all branches, not just the main branch. A developer who created a test branch with anonymised data two quarters ago may have forgotten about it entirely. PlanetScale's branch management does not automatically expire old branches, and the CLOUD Act does not distinguish between "active" and "forgotten" data copies.

This is structurally similar to the Neon branching CLOUD Act problem — but with an important difference: PlanetScale's branches are more commonly used with production schema data than Neon's branches, which are typically used for schema-identical preview environments.

PlanetScale Insights: Query Text as Personal Data

PlanetScale Insights is a query analytics feature that captures slow queries, execution plans, and query frequency distributions. The compliance problem: the text of a SQL query may itself constitute personal data.

Consider a query like:

SELECT * FROM users WHERE email = 'maria.schmidt@example.de' AND status = 'active'

This query, captured verbatim in PlanetScale Insights, contains the personal data of Maria Schmidt. Under GDPR Art. 4(1), personal data means "any information relating to an identified or identifiable natural person". An email address in a WHERE clause qualifies.

PlanetScale Insights retains query data for analytics purposes. The retention window, the geographic location of Insights data, and the sub-processors who can access it are not always clearly documented. For EU developers processing EU personal data, this is an Art. 35 DPIA trigger.

Practical Python: PlanetScale GDPR Compliance Analyser

#!/usr/bin/env python3
"""
PlanetScale GDPR Compliance Analyser
Assesses CLOUD Act exposure and GDPR risk for PlanetScale deployments.
"""

from dataclasses import dataclass, field
from enum import Enum


class RiskLevel(Enum):
    CRITICAL = "CRITICAL"
    HIGH = "HIGH"
    MEDIUM = "MEDIUM"
    LOW = "LOW"


@dataclass
class ComplianceFinding:
    service: str
    risk: RiskLevel
    gdpr_articles: list[str]
    cloud_act_vector: str
    recommendation: str


@dataclass
class PlanetScaleDeployment:
    region: str
    has_global_replicas: bool = False
    uses_insights: bool = True
    branch_count: int = 1
    has_boost: bool = False
    stores_personal_data: bool = True


def analyse_planetscale_gdpr(deployment: PlanetScaleDeployment) -> list[ComplianceFinding]:
    findings: list[ComplianceFinding] = []

    if deployment.stores_personal_data:
        findings.append(ComplianceFinding(
            service="Production Database (Vitess/MySQL)",
            risk=RiskLevel.CRITICAL,
            gdpr_articles=["Art. 44", "Art. 46", "Art. 28"],
            cloud_act_vector="PlanetScale Inc. (US) → AWS " + deployment.region,
            recommendation="Migrate to EU-native managed MySQL (sota.io, Hetzner, Scaleway) "
                           "or self-hosted Vitess on EU infrastructure"
        ))

    if deployment.branch_count > 1:
        findings.append(ComplianceFinding(
            service=f"Database Branches ({deployment.branch_count} branches)",
            risk=RiskLevel.HIGH,
            gdpr_articles=["Art. 5(1)(e)", "Art. 17", "Art. 35"],
            cloud_act_vector="All branches in same US-controlled environment as production",
            recommendation="Audit all open branches — delete branches containing personal data. "
                           "Use anonymised seed data for development branches."
        ))

    if deployment.uses_insights:
        findings.append(ComplianceFinding(
            service="PlanetScale Insights (Query Analytics)",
            risk=RiskLevel.HIGH,
            gdpr_articles=["Art. 25", "Art. 35", "Art. 5(1)(b)"],
            cloud_act_vector="Query text (may contain personal data) stored in US-controlled analytics system",
            recommendation="Disable Insights or sanitise queries via application-level prepared "
                           "statements to prevent personal data in query text"
        ))

    if deployment.has_global_replicas:
        findings.append(ComplianceFinding(
            service="Global Read Replicas",
            risk=RiskLevel.CRITICAL,
            gdpr_articles=["Art. 44", "Art. 46", "Recital 101"],
            cloud_act_vector="Each replica region = additional CLOUD Act exposure point",
            recommendation="Map all replica regions. Non-EEA replicas require Art. 46 transfer "
                           "mechanism AND CLOUD Act assessment for each region."
        ))

    if deployment.has_boost:
        findings.append(ComplianceFinding(
            service="PlanetScale Boost (Query Cache)",
            risk=RiskLevel.MEDIUM,
            gdpr_articles=["Art. 5(1)(b)", "Art. 25"],
            cloud_act_vector="Cached query results may include personal data in US-controlled cache layer",
            recommendation="Evaluate whether cached queries return personal data. "
                           "If yes: disable Boost for affected query patterns."
        ))

    return findings


def generate_report(deployment: PlanetScaleDeployment) -> None:
    findings = analyse_planetscale_gdpr(deployment)

    print("=" * 70)
    print("PLANETSCALE GDPR / CLOUD ACT COMPLIANCE REPORT")
    print(f"Region: {deployment.region} | Branches: {deployment.branch_count}")
    print("=" * 70)

    for finding in findings:
        print(f"\n[{finding.risk.value}] {finding.service}")
        print(f"  GDPR Articles: {', '.join(finding.gdpr_articles)}")
        print(f"  CLOUD Act Vector: {finding.cloud_act_vector}")
        print(f"  Recommendation: {finding.recommendation}")

    critical = sum(1 for f in findings if f.risk == RiskLevel.CRITICAL)
    high = sum(1 for f in findings if f.risk == RiskLevel.HIGH)
    print(f"\nSummary: {critical} CRITICAL | {high} HIGH findings")
    print("Conclusion: PlanetScale is NOT GDPR-compliant for EU personal data")
    print("Root cause: US entity jurisdiction (CLOUD Act) cannot be resolved by SCCs")


if __name__ == "__main__":
    # Typical EU developer deployment
    deployment = PlanetScaleDeployment(
        region="AWS eu-central-1 (Frankfurt)",
        has_global_replicas=False,
        uses_insights=True,
        branch_count=5,
        has_boost=False,
        stores_personal_data=True,
    )
    generate_report(deployment)

Running this for a typical EU deployment (Frankfurt region, 5 branches, Insights enabled) produces:

PLANETSCALE GDPR / CLOUD ACT COMPLIANCE REPORT
Region: AWS eu-central-1 (Frankfurt) | Branches: 5
[CRITICAL] Production Database (Vitess/MySQL)
  GDPR Articles: Art. 44, Art. 46, Art. 28
  CLOUD Act Vector: PlanetScale Inc. (US) → AWS eu-central-1 (Frankfurt)
[HIGH] Database Branches (5 branches)
  GDPR Articles: Art. 5(1)(e), Art. 17, Art. 35
  CLOUD Act Vector: All branches in same US-controlled environment as production
[HIGH] PlanetScale Insights (Query Analytics)
  GDPR Articles: Art. 25, Art. 35, Art. 5(1)(b)
  CLOUD Act Vector: Query text stored in US-controlled analytics system
Summary: 1 CRITICAL | 2 HIGH findings

The Non-Blocking Schema Changes Compliance Angle

PlanetScale's schema change workflow is genuinely innovative: instead of running ALTER TABLE directly (which locks tables), PlanetScale creates a shadow copy of the table, applies the schema change, and runs an online migration to sync data. This avoids MySQL's traditional blocking DDL problem.

The compliance implication that is often overlooked: the shadow table contains a full copy of your production data during the migration window. For a table containing personal data:

  1. Shadow table is created (copy of schema)
  2. Data is incrementally copied from live table to shadow table
  3. Shadow table catches up via binary log replay
  4. Tables are swapped
  5. Old table is dropped

During steps 2-4, two full copies of your personal data exist simultaneously within the PlanetScale infrastructure. Under GDPR Art. 5(1)(e) (storage limitation), you should be able to document the retention window for these intermediate copies. PlanetScale does not expose this metadata in its standard dashboard views.

This is not a reason to avoid schema migrations — but it is a reason to document them in your ROPA (Records of Processing Activities, Art. 30) and to understand that schema changes create temporary data duplication within a US-controlled environment.

PlanetScale Pricing Changes: The Business Risk

In 2024, PlanetScale made significant pricing changes, removing the free tier and introducing new pricing that substantially increased costs for many use cases. This created a large cohort of teams who needed to migrate their MySQL workloads.

For EU teams, this migration moment is an opportunity to evaluate jurisdiction alongside pricing. A team already migrating from PlanetScale's free tier to a paid alternative faces the same migration complexity whether they choose another US-based service or an EU-native one — but the GDPR risk profiles are very different.

Migration TargetJurisdictionEst. Monthly CostGDPR Status
AWS RDS MySQLUS entity (CLOUD Act)€50-300+Non-compliant (US law)
Aiven for MySQLFinnish entity, EU-HQ€25-150Compliant (EU law, but check sub-processors)
Managed MySQL on sota.ioEU entityFrom €9/moCompliant (EU infrastructure)
Self-hosted MySQL (Hetzner)EU infrastructure€5-20/mo (VPS)Compliant (you control it)
Self-hosted Vitess (Hetzner)EU infrastructure€15-50/moCompliant (Vitess OSS on EU servers)

EU-Native PlanetScale Alternatives

1. Managed MySQL on sota.io

sota.io is an EU-native Platform-as-a-Service built specifically to address the CLOUD Act jurisdiction problem. Your data stays within the EU under EU law, and sota.io is not subject to CLOUD Act compulsion.

For teams migrating from PlanetScale, sota.io provides:

The primary trade-off: sota.io doesn't include Vitess's horizontal sharding capabilities. For the vast majority of workloads — those that don't require multi-terabyte sharded MySQL — this is irrelevant. PlanetScale's sharding is genuinely necessary for YouTube-scale workloads; it is marketing for most SaaS applications.

2. Self-Hosted Vitess on Hetzner

Vitess is open source (Apache 2.0, CNCF graduated). Running it on EU infrastructure gives you PlanetScale's core functionality — horizontal sharding, non-blocking schema changes, connection pooling — without the US jurisdiction problem.

# Vitess on Hetzner (minimal setup)
# 1. Provision Hetzner VPS (Frankfurt, CPX31 = 4 vCPU, 8GB, €12.47/mo)
# 2. Install Vitess
curl -L https://github.com/vitessio/vitess/releases/download/v20.0.0/vitess-20.0.0-linux_amd64.tar.gz \
  | tar xzf - -C /usr/local

# 3. Configure VTTablet + VTGate (see Vitess documentation)
# Your connection string: mysql://user:pass@vtgate.internal:3306/keyspace

The operational complexity of self-hosted Vitess is real: it requires understanding VTGate, VTTablet, topology service (etcd/ZooKeeper), and cell configuration. For teams with a dedicated platform engineer, it is manageable. For small teams, managed MySQL is usually more appropriate.

3. Aiven for MySQL

Aiven is a Finnish company (Helsinki, EU-HQ) that offers managed MySQL. Aiven runs on multiple cloud providers including Hetzner in Germany. As an EU entity, Aiven is not directly subject to CLOUD Act compulsion.

Important caveat: verify Aiven's sub-processor list. If your specific Aiven MySQL deployment runs on AWS infrastructure in the EU, the underlying AWS infrastructure is US-controlled — but Aiven itself as the data processor is EU-based. This is legally different from PlanetScale's situation, but worth understanding for your DPA.

4. SingleStore (European Plans)

SingleStore offers EU-based managed database options with EU-domiciled contracts for enterprise customers. It supports MySQL-compatible queries and has strong analytics capabilities. Pricing is enterprise-tier; not suitable for small teams.

5. Hetzner Managed MySQL via Coolify

Coolify is an open-source PaaS that runs on your own infrastructure, including Hetzner. Coolify includes a one-click MySQL deployment with automated backups, SSL, and a web interface for common database management tasks. This gives PlanetScale-like developer experience on EU infrastructure at Hetzner prices.

Migration Guide: PlanetScale → EU-Native MySQL

Step 1: Audit Your Branches

Before migrating, audit all open branches:

# PlanetScale CLI - list all branches
pscale branch list your-database-name

# For each branch: determine if it contains personal data
# Delete branches that are no longer needed
pscale branch delete your-database-name branch-name

Under GDPR Art. 17, you have an obligation to delete data that is no longer necessary. Old development branches containing production data copies are a compliance liability.

Step 2: Export Your Schema and Data

# Export schema only
pscale shell your-database main -- --execute "SHOW CREATE TABLE users\G"

# Full dump via mysqldump (using PlanetScale connection string)
mysqldump \
  --host your-host.aws.connect.psdb.cloud \
  --user your-username \
  --password \
  --ssl-mode=REQUIRED \
  --no-tablespaces \
  your-database > backup.sql

Step 3: Provision EU-Native MySQL

# On sota.io: create MySQL database from dashboard
# Or via Hetzner Coolify: one-click MySQL 8.0 deployment

# Import your dump
mysql \
  --host your-eu-mysql-host \
  --user your-username \
  --password \
  --database your-database < backup.sql

Step 4: Update Application Connection Strings

PlanetScale uses standard MySQL protocol — any MySQL-compatible driver works. Update your connection string:

# Before (PlanetScale)
DATABASE_URL="mysql://user:pass@aws.connect.psdb.cloud:3306/dbname?ssl=true"

# After (sota.io / EU-native MySQL)
DATABASE_URL="mysql://user:pass@eu-mysql.your-host.sota.io:3306/dbname?ssl=true"

Your ORM (Prisma, Drizzle, TypeORM, SQLAlchemy) does not need to change — they all speak standard MySQL protocol.

Step 5: Schema Migration Workflow Without PlanetScale

PlanetScale's non-blocking schema changes are a real operational advantage. On standard MySQL 8.0, you have two approaches:

Option A: MySQL 8.0 Online DDL (built-in, no tools needed)

-- MySQL 8.0 supports online DDL for most operations
ALTER TABLE users ADD COLUMN last_login TIMESTAMP, ALGORITHM=INPLACE, LOCK=NONE;

Option B: gh-ost (GitHub's online schema change tool, open source)

gh-ost \
  --host=your-eu-mysql-host \
  --database=your-database \
  --table=users \
  --alter="ADD COLUMN last_login TIMESTAMP" \
  --execute

gh-ost implements the same shadow-table approach as PlanetScale — but you run it on your own infrastructure, with full visibility into the intermediate table lifecycle.

Summary: PlanetScale GDPR Risk Assessment

FactorPlanetScale Status
Legal entityUS (Delaware inc., San Mateo, CA HQ)
CLOUD Act applicabilityYES — compelled disclosure possible
EU region availabilityYES (Frankfurt, via AWS)
CLOUD Act resolved by EU regionNO — geographic, not legal
SCCs provide full protectionNO — Schrems II, CLOUD Act §2713
Vitess available EU-nativelyYES (OSS, self-host on Hetzner)
GDPR-compliant alternativeYES — sota.io, Hetzner, self-hosted Vitess

PlanetScale is an excellent product for US-domiciled teams with US legal exposure. For EU teams processing EU personal data, the CLOUD Act jurisdiction problem makes it non-compliant regardless of which region you select.

The good news: MySQL is the most portable database format that exists. Migration tooling is mature (mysqldump, gh-ost, mydumper), driver compatibility is universal, and EU-native alternatives can be operational in under an hour.

sota.io is an EU-native platform that replaces PlanetScale's managed database component — without the jurisdiction problem. Try it free at sota.io.

EU-Native Hosting

Ready to move to EU-sovereign infrastructure?

sota.io is a German-hosted PaaS — no CLOUD Act exposure, no US jurisdiction, full GDPR compliance by design. Deploy your first app in minutes.