Connect MySQL to AI Dashboards and Agents
MySQL is probably the most-deployed relational database in the world. Every WordPress site, every Laravel app, most Rails and Django projects from the last fifteen years — they all write to MySQL. The data is there. User signups, orders, feature usage, subscription events, everything your app tracks — it's sitting in InnoDB tables right now.
Getting analytics out of it is where things get ugly. You either export CSVs from phpMyAdmin like it's 2009, stand up a Metabase instance and maintain it forever, or build an ETL pipeline into a warehouse so your BI tool has something to query. All of that is real engineering work for what should be a straightforward problem: "show me a chart of what's in my database."
There's a shorter path. Connect MySQL directly, query it with SQL or plain English, build dashboards from the results, and join MySQL data with your other sources — Stripe, HubSpot, Postgres, Google Sheets — without moving anything into a warehouse first.
Connecting MySQL: the practical details
Fastero connects to MySQL over an encrypted TLS connection using read-only credentials. You provide a host, port, username, password, and database name — the same fields you'd put in any MySQL client. If your MySQL instance is behind a firewall or VPC, SSH tunneling is supported.
The connection is read-only by design. Create a dedicated user with SELECT privileges and nothing else:
CREATE USER 'fastero_reader'@'%' IDENTIFIED BY 'strong_password_here';
GRANT SELECT ON your_database.* TO 'fastero_reader'@'%';
FLUSH PRIVILEGES;Once connected, Fastero discovers your schema automatically — but if you want to understand what you're working with before building anything, INFORMATION_SCHEMA is your friend:
SELECT table_name, table_rows, data_length / 1024 / 1024 AS size_mb
FROM INFORMATION_SCHEMA.TABLES
WHERE table_schema = 'your_database'
ORDER BY table_rows DESC;This gives you a quick inventory: which tables have data worth querying, which are tiny lookup tables, which are unexpectedly large. It's the first thing I run on any MySQL database I haven't worked with before — faster than scrolling through a GUI and more informative than SHOW TABLES.
Web app analytics straight from MySQL
Most web app databases share a common shape: users, orders or subscriptions, and some kind of events or activity_log table. The analytics queries you actually need are more standard than you'd think.
User signups over time (weekly cohorts)
SELECT
DATE_FORMAT(created_at, '%Y-%u') AS signup_week,
COUNT(*) AS signups
FROM users
WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL 12 WEEK)
GROUP BY signup_week
ORDER BY signup_week;Funnel analysis: signup to activation to paid
WITH signups AS (
SELECT id AS user_id, created_at AS signup_at
FROM users
WHERE created_at >= '2026-06-01'
AND created_at < '2026-07-01'
),
activated AS (
SELECT DISTINCT e.user_id
FROM events e
JOIN signups s ON s.user_id = e.user_id
WHERE e.event_name = 'activated'
AND e.created_at BETWEEN s.signup_at
AND DATE_ADD(s.signup_at, INTERVAL 14 DAY)
),
paid AS (
SELECT DISTINCT sub.user_id
FROM subscriptions sub
JOIN signups s ON s.user_id = sub.user_id
WHERE sub.status = 'active'
AND sub.started_at BETWEEN s.signup_at
AND DATE_ADD(s.signup_at, INTERVAL 30 DAY)
)
SELECT
(SELECT COUNT(*) FROM signups) AS step_1_signups,
(SELECT COUNT(*) FROM activated) AS step_2_activated,
(SELECT COUNT(*) FROM paid) AS step_3_paid,
ROUND(100.0 * (SELECT COUNT(*) FROM activated) /
NULLIF((SELECT COUNT(*) FROM signups), 0), 1) AS pct_activated,
ROUND(100.0 * (SELECT COUNT(*) FROM paid) /
NULLIF((SELECT COUNT(*) FROM activated), 0), 1) AS pct_activated_to_paid;Revenue per customer (lifetime)
SELECT
u.id,
u.email,
u.created_at AS signup_date,
COUNT(o.id) AS total_orders,
SUM(o.amount_cents) / 100.0 AS lifetime_revenue,
DATEDIFF(CURDATE(), u.created_at) AS days_since_signup,
ROUND(SUM(o.amount_cents) / 100.0 /
GREATEST(DATEDIFF(CURDATE(), u.created_at) / 30.0, 1), 2) AS monthly_revenue
FROM users u
LEFT JOIN orders o ON o.user_id = u.id AND o.status = 'completed'
GROUP BY u.id, u.email, u.created_at
ORDER BY lifetime_revenue DESC
LIMIT 50;These queries work on any typical SaaS or e-commerce MySQL schema — rename the tables and columns and they run as-is. In Fastero, you can save these as dashboard widgets that refresh on a schedule, so the numbers are always current without anyone running queries manually.
Fastero
Connect your database. Ask questions. Get dashboards.
Postgres, BigQuery, Snowflake, and 10+ sources — live-connected, AI-powered, no dashboard builder learning curve.
Try free →Point it at your read replica
If you're running any production MySQL deployment beyond a side project, you probably have a read replica. Connect Fastero to that replica instead of your primary.
This is the right default for analytics workloads. Your dashboard queries — aggregations over large tables, cohort self-joins, GROUP BY over months of data — are exactly the kind of queries that compete with production writes for InnoDB buffer pool space. A read replica absorbs all of that with zero impact on your application's response times.
The connection setup is identical. Same credentials, different hostname. If you're on AWS RDS, it's your reader endpoint. On PlanetScale, it's a read-only branch. On a self-managed replica, it's whatever host you've configured for async replication.
Finding slow queries with performance_schema
While you're connected, performance_schema gives you something most analytics tools don't: visibility into MySQL itself. This query surfaces your slowest statements:
SELECT
DIGEST_TEXT AS query_pattern,
COUNT_STAR AS executions,
ROUND(SUM_TIMER_WAIT / 1e12, 2) AS total_seconds,
ROUND(AVG_TIMER_WAIT / 1e12, 4) AS avg_seconds,
SUM_ROWS_EXAMINED AS rows_examined
FROM performance_schema.events_statements_summary_by_digest
WHERE SCHEMA_NAME = 'your_database'
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 20;You can turn this into a dashboard widget too — a "Top 20 Slowest Queries" panel that refreshes daily. It's the kind of operational visibility that usually requires a dedicated monitoring tool. Here it's just another SQL query on a connection you already have.
Cross-source joins: MySQL + everything else
This is where MySQL-only tools hit a wall. Your app data is in MySQL, but your revenue is in Stripe, your pipeline is in HubSpot, your marketing spend is in Google Ads, and your targets are in a Google Sheet. No single-database query can answer "which marketing channels drive actual revenue, not just signups."
Fastero's cross-source DuckDB store solves this. Pull tables from your MySQL connection and any other connected source into DuckDB, then write standard SQL across all of them.
MySQL users + Stripe revenue
SELECT
m.email,
m.created_at AS signup_date,
s.amount / 100.0 AS mrr,
s.current_period_end
FROM mysql_app.users m
JOIN stripe.subscriptions s
ON m.stripe_customer_id = s.customer_id
WHERE s.status = 'active'
ORDER BY mrr DESC;MySQL + Postgres (the migration scenario)
This one comes up constantly. You're migrating from MySQL to Postgres, or you've already moved some services over and now your data lives in both. Instead of building a pipeline to reconcile them, just connect both and query across them:
SELECT
pg.deal_id,
pg.deal_value,
my.user_email,
my.signup_source
FROM postgres_crm.deals pg
JOIN mysql_app.users my
ON pg.contact_email = my.user_email
WHERE pg.stage = 'closed_won'
AND my.created_at >= '2026-01-01';No intermediate staging tables, no nightly sync jobs. Both databases stay where they are — you just query across them. This is particularly useful during migrations where you need to validate that both systems agree before cutting over.
Ask questions in plain English
Not every question needs a hand-written query. Fastero's AI agent understands your MySQL schema — table names, column types, relationships — and generates SQL from natural language.
"Show me weekly signups for the last quarter, broken down by referral source" turns into a GROUP BY query against your users table. "Which customers have the highest lifetime value but haven't logged in for 30 days" becomes a join between users, orders, and events with a MAX(created_at) filter. The agent writes MySQL-dialect SQL, runs it against your connection, and returns the result as a chart or table.
For ad-hoc exploration — the kind of question that comes up in a Monday meeting and would normally go into a Slack thread to an engineer — this is faster than writing the query yourself and much faster than exporting a CSV.
From query to dashboard in minutes
The workflow from here is straightforward. Write a query (or let the agent write it), verify the results look right, pin it as a dashboard widget. Repeat for each metric you care about. Set the dashboard to refresh on a schedule — hourly, daily, whatever fits.
You end up with a live dashboard powered directly by your MySQL database, alongside data from every other source you've connected. No warehouse. No ETL. No infrastructure to maintain beyond the database you're already running.
Try Fastero free — connect your MySQL database and build dashboards in minutes, not months. No credit card required.

