Syncing MySQL to BigQuery

There are three real ways to do this, and the right one depends less on your data volume than on who is going to maintain it at 2am. Here's the honest comparison.

The part everyone underestimates

Moving the data once is easy. mysqldump, convert, bq load, done in an afternoon. Keeping it moving is the actual project: schema changes break loads, full refreshes get slower every month, and the tables that grow fastest are usually logs nobody queries.

The second underestimate is the read side. Whatever tool you choose, the extract runs against a server that is also serving your application. A full refresh is a long sequential scan over your largest tables, and it holds nothing back out of politeness. Most teams get away with it for months, then schedule it at 3am after the first bad night.

CDC via the binlog avoids the repeated scans, but raises the bar on access: ROW-format binlog, sufficient retention, a replication user, a spare server id. On managed or shared hosting, that's frequently just not available — which is what pushes people back to full refreshes.

Three ways to do it

All three work. They differ in what they cost you — in money, in maintenance, and in load on the database your customers are using right now.

Scheduled dump and load

Export tables to CSV or Parquet, load them into BigQuery on a cron.

  • Simple, transparent, no vendor
  • Cheap at small and medium scale
  • Full scans against production every run
  • Slower every month as tables grow
  • Schema changes are yours to catch

CDC replication

Datastream, Debezium or similar read the binlog and stream changes into BigQuery.

  • Near-real-time
  • No repeated full scans once seeded
  • Needs ROW binlog, retention and replication privileges
  • Often impossible on managed hosting
  • More moving parts to own and monitor

Clone to PostgreSQL first

BeQuery

BeQuery maintains an isolated, verified PostgreSQL copy of the MySQL database. Query it directly, or run your dump-and-load against the copy instead of the live server.

  • The extract moves off production permanently
  • Type quirks handled — MySQL zero-dates and unsigned ints don't break the load
  • Row counts verified against the source each sync
  • Often removes the need for the warehouse in the first place
  • An extra hop if BigQuery is genuinely required
  • Scheduled rather than streaming

The path through a clone, step by step

  1. 1

    Connect your store to BeQuery

    Read-only MySQL credentials, host and port. BeQuery connects, discovers your tables and clones them into an isolated PostgreSQL schema that only your team can reach.

  2. 2

    Let it sync on a schedule

    Each sync rebuilds the copy and verifies it — row counts are checked against the source, so you know the data is complete rather than hoping it is. Production only ever sees a read.

  3. 3

    Query it directly, or load it onward

    Most people stop here: the clone is a real PostgreSQL database with a SQL editor, ready-made insights and BI connections. If you specifically need BigQuery, export the tables you care about from the clone and load them with bq load — the extract now runs against the copy, not your shop.

  4. 4

    Schedule the load

    Run the export-and-load step on your own cron, after the sync completes. Because it reads the clone, it can run as often and as heavily as you like without a single query reaching production.

Do you actually need a warehouse?

Worth asking before you build anything. A warehouse is the right tool for some of these situations and overkill for the rest.

Yes — build it

  • Several data sources that need joining in one place
  • Volumes or query patterns a single database can't serve
  • An existing Google Cloud estate and BigQuery skills on the team

Probably not — a clone is enough

  • One MySQL database and a need for reporting on it
  • No one whose job is to own a data pipeline
  • PostgreSQL would comfortably hold everything you have

Common questions

What breaks most often in a MySQL to BigQuery load?

Type edge cases, almost every time. MySQL's '0000-00-00' dates aren't valid timestamps anywhere else, unsigned bigints overflow signed targets, and zero-length strings versus NULL flip meaning between engines. BeQuery's type mapper deals with these when it clones, which is one class of failure you stop debugging.

Can BeQuery stream changes in real time?

Not today. Sync is scheduled — nightly through to roughly every minute depending on plan. Binlog-based CDC is on the roadmap and gated on the source database granting replication access, which is exactly the constraint that makes DIY CDC hard in the first place.

Is BeQuery a BigQuery connector?

No, and we'd rather say so plainly. BeQuery clones your store's MySQL database into an isolated, verified PostgreSQL copy. There is no one-click push into BigQuery. What BeQuery removes is the hard part — pulling data out of a live shop safely and keeping it fresh — after which loading into BigQuery is an ordinary export-and-load step against a copy that nobody depends on.

Why not just point an ETL tool straight at my production database?

You can, and for a small shop it may be fine. The catch is that every full refresh reads your production tables while customers are shopping, and the tables that grow fastest are usually tracking and log tables you don't want in a warehouse anyway. Extracting from a copy means a heavy read can never turn into a slow checkout.

How fresh is the data?

As fresh as your sync schedule — nightly on the lower plans, hourly and faster on the higher ones. For a warehouse used for reporting, nightly is usually what people land on regardless of what the tool supports.

See it on your own store first

Free tier, no credit card, read-only access. Production is never written to — and you can explore the demo store before connecting anything.