Introduction to Cloud SQL Monitoring
What Is Cloud SQL Monitoring?
Cloud SQL Monitoring is the practice of collecting, visualizing, and acting upon operational metrics from your managed database instances. In Google Cloud, Cloud SQL provides a fully managed MySQL, PostgreSQL, or SQL Server service, and Cloud Monitoring (formerly Stackdriver) automatically ingests dozens of instance-level and database-level metrics. These metrics range from basic resource utilization—CPU, memory, disk usage—to database-specific signals like connection counts, replication lag, transaction throughput, and query performance indicators.
Monitoring is not merely about watching dashboards. It encompasses the entire feedback loop: instrumenting your database tier, aggregating telemetry data, defining thresholds for acceptable performance, and triggering alerts when those thresholds are breached. A well-tuned monitoring setup gives you early warning of capacity pressure, query inefficiencies, or configuration drift before they manifest as user-facing outages.
Why Monitoring Matters for Cloud SQL
Managed services abstract away many operational burdens—patching, backups, high availability failover—but they do not eliminate the need for observability. Your application's data tier is often the most stateful and performance-sensitive component of your architecture. A slow query or a saturated connection pool can degrade the entire user experience. Monitoring matters because:
- Cost optimization: Over-provisioned instances waste budget; under-provisioned ones cause throttling and downtime. Metrics guide right-sizing decisions.
- SLA compliance: You can define SLOs (Service Level Objectives) around latency, availability, and durability, then alert on SLO burn rate.
- Incident response: Alarms shorten mean-time-to-detection (MTTD) from hours to seconds, letting on-call engineers triage before customers notice.
- Capacity planning: Trend lines on storage growth, IOPS consumption, and connection counts let you forecast hardware needs weeks or months ahead.
- Security and audit: Monitoring login failures, admin API calls, and SSL/TLS termination metrics helps detect misconfigurations or intrusion attempts.
Key Cloud SQL Metrics
System-Level Metrics (Infrastructure)
Cloud Monitoring collects these metrics automatically for every Cloud SQL instance at 1-minute granularity (or 1-second for select high-resolution metrics). They require no additional agent or configuration:
- CPU utilization –
cloudsql.googleapis.com/database/cpu/utilization– fraction of allocated vCPU in use. - Memory usage –
cloudsql.googleapis.com/database/memory/utilization– ratio of used RAM to instance total. - Disk utilization –
cloudsql.googleapis.com/database/disk/utilization– percentage of provisioned disk consumed. Reaching 100% can cause instance shutdown. - Disk throughput –
cloudsql.googleapis.com/database/disk/read_bytes_per_secondandwrite_bytes_per_second– raw IO throughput. - Disk IOPS –
cloudsql.googleapis.com/database/disk/read_ops_per_secondandwrite_ops_per_second– IO operations per second. - Network bytes –
cloudsql.googleapis.com/database/network/received_bytes_countandsent_bytes_count– ingress/egress traffic.
Database-Specific Metrics
These metrics are surfaced by the Cloud SQL metadata agent running inside the instance, and they vary slightly by database engine (MySQL, PostgreSQL, SQL Server):
- Active connections –
cloudsql.googleapis.com/database/postgresql/num_backends(PostgreSQL) orcloudsql.googleapis.com/database/mysql/Connections(MySQL). Tracks connection count, crucial for detecting connection leaks. - Replication lag –
cloudsql.googleapis.com/database/mysql/Seconds_Behind_Master(MySQL read replicas) – seconds that the replica lags behind the primary. High values indicate replication bottleneck. - Transaction throughput –
cloudsql.googleapis.com/database/postgresql/xact_commitandxact_rollback– commits and rollbacks per second. - Lock waits –
cloudsql.googleapis.com/database/postgresql/lock_wait_count– how often queries wait on locks. - Cache hit ratio –
cloudsql.googleapis.com/database/mysql/Innodb_buffer_pool_read_hit_ratio(MySQL) – fraction of page reads served from buffer pool. A drop signals memory pressure. - Long-running queries –
cloudsql.googleapis.com/database/postgresql/longest_query_running_seconds– the longest currently executing query duration.
Log-Based Metrics
You can create user-defined metrics from Cloud SQL audit logs and query logs. For example, extract slow queries from the PostgreSQL log_duration or MySQL slow query log, then count them as a custom metric:
# Example: Create a log-based metric from slow queries in Cloud Logging
gcloud logging metrics create slow_query_count \
--description="Count of slow queries (>5s)" \
--log-filter='resource.type="cloudsql_database"
textPayload:"duration:"
AND jsonPayload.durationSec > 5'
Accessing Cloud SQL Metrics
Using the Cloud Monitoring Console
Navigate to Monitoring → Metrics Explorer in the Google Cloud Console. Select the resource type cloudsql_database and pick a metric. You can filter by database instance ID, database engine type, or region. The Metrics Explorer lets you overlay multiple time series, adjust time ranges, and experiment with aggregations before committing them to a dashboard.
Querying Metrics with MQL (Monitoring Query Language)
MQL is the declarative language for querying, transforming, and analyzing Cloud Monitoring metrics. It supports filtering, alignment windows, sliding windows, joins, and ratio computations. Here are practical MQL snippets you can run in Metrics Explorer or embed in dashboards:
# CPU utilization across all Cloud SQL MySQL instances, 1-hour rolling average
fetch cloudsql_database::cloudsql.googleapis.com/database/cpu/utilization
| filter metric.database_engine == 'MYSQL'
| align delta_align(1h)
| every 1h
| group_by [resource.project_id, resource.database_id], mean(val())
| window 1h
# Disk utilization percentage with a threshold indicator (above 85% is critical)
fetch cloudsql_database::cloudsql.googleapis.com/database/disk/utilization
| align mean_align(5m)
| every 5m
| window 5m
| map val() < 0.85 => 'ok', val() >= 0.85 => 'critical'
# Ratio of failed to successful database connections
fetch cloudsql_database::cloudsql.googleapis.com/database/mysql/Connections
| filter metric.connection_state == 'FAILED'
| align rate(5m)
| every 5m
| group_by [], sum(val())
| div(
fetch cloudsql_database::cloudsql.googleapis.com/database/mysql/Connections
| filter metric.connection_state == 'SUCCESSFUL'
| align rate(5m)
| every 5m
| group_by [], sum(val())
)
# PostgreSQL replication lag in bytes (for read replicas)
fetch cloudsql_database::cloudsql.googleapis.com/database/postgresql/replication/replay_lag_bytes
| align mean_align(1m)
| every 1m
| group_by [resource.database_id], max(val())
Using the Cloud Monitoring API (Python)
When you need to integrate metrics into your own automation, CI/CD pipelines, or custom tooling, the Cloud Monitoring API provides programmatic access. Here's a Python example that retrieves the 5-minute average CPU utilization for a specific instance:
from google.cloud import monitoring_v3
from datetime import datetime, timedelta
import time
client = monitoring_v3.MetricServiceClient()
project_id = "my-project-id"
project_name = f"projects/{project_id}"
# Define the time window: last 30 minutes
now = datetime.utcnow()
interval = monitoring_v3.TimeInterval(
start_time=(now - timedelta(minutes=30)).isoformat() + "Z",
end_time=now.isoformat() + "Z"
)
# Build the request for CPU utilization
request = monitoring_v3.ListTimeSeriesRequest(
name=project_name,
filter='resource.type="cloudsql_database" '
'metric.type="cloudsql.googleapis.com/database/cpu/utilization" '
'resource.label.database_id="my-instance-id"',
interval=interval,
view=monitoring_v3.ListTimeSeriesRequest.TimeSeriesView.FULL,
aggregation=monitoring_v3.Aggregation(
alignment_period={"seconds": 300}, # 5-minute alignment
per_series_aligner=monitoring_v3.Aggregation.Aligner.ALIGN_MEAN
)
)
for ts in client.list_time_series(request):
print(f"Metric: {ts.metric.type}")
for point in ts.points:
end_time = point.interval.end_time
value = point.value.double_value
print(f" {end_time}: CPU {value:.3f}")
Setting Up Alarms and Alerting Policies
Why Alerting Matters
Metrics alone are passive; alarms make them active. An alerting policy detects when a metric crosses a threshold, sustains a condition over time, or deviates from a forecast. Without alerting, you depend on someone noticing a dashboard anomaly—often hours after impact begins. Well-configured alarms route to email, Slack, PagerDuty, or webhooks, triggering automated runbooks or manual intervention.
Creating Alerting Policies via gcloud CLI
The gcloud command-line tool can create alerting policies declaratively using YAML or JSON files. Here's a complete example that alerts when CPU utilization exceeds 90% for more than 5 minutes on any Cloud SQL instance in a project:
# alert_policy_cpu.yaml
displayName: "Cloud SQL High CPU Alert"
combiner: OR
conditions:
- displayName: "CPU utilization > 90% for 5 minutes"
conditionThreshold:
filter: >
resource.type="cloudsql_database"
metric.type="cloudsql.googleapis.com/database/cpu/utilization"
aggregations:
- alignmentPeriod: 300s
perSeriesAligner: ALIGN_MEAN
comparison: COMPARISON_GT
thresholdValue: 0.90
duration:
seconds: 300
trigger:
count: 1
conditionMonitoringQueryLanguage: false
notificationChannels:
- projects/my-project-id/notificationChannels/1234567890
- projects/my-project-id/notificationChannels/2345678901
# Apply the policy
gcloud alpha monitoring policies create --policy-from-file=alert_policy_cpu.yaml
Creating Alerting Policies via MQL (Condition Monitoring Query Language)
For more complex conditions—ratios, multi-metric joins, or forecast-based thresholds—use MQL conditions. The example below alerts when disk utilization is forecast to exceed 95% within 24 hours based on linear extrapolation:
# alert_policy_disk_forecast.yaml
displayName: "Cloud SQL Disk Full Forecast"
combiner: OR
conditions:
- displayName: "Disk will be >95% in 24h (forecast)"
conditionMonitoringQueryLanguage: true
conditionMql:
query: >
fetch cloudsql_database::cloudsql.googleapis.com/database/disk/utilization
| forecast_linear(24h)
| condition val() >= 0.95
duration:
seconds: 300
trigger:
count: 1
notificationChannels:
- projects/my-project-id/notificationChannels/1234567890
gcloud alpha monitoring policies create --policy-from-file=alert_policy_disk_forecast.yaml
Alerting on Connection Exhaustion
Connection exhaustion is a common production failure mode. The following alert fires when active connections exceed 80% of the configured max_connections for a PostgreSQL instance:
# Alert when PostgreSQL connections > 80% of max (assumed max_connections=400)
# MQL: ratio of current connections to 400
fetch cloudsql_database::cloudsql.googleapis.com/database/postgresql/num_backends
| align mean_align(5m)
| every 5m
| map val() / 400.0
| condition val() >= 0.80
Notification Channels and Escalation
Cloud Monitoring supports notification channels for Email, SMS, Slack, PagerDuty, Pub/Sub, and Webhooks. You can create them in the console or via gcloud:
# Create an email notification channel
gcloud alpha monitoring channels create \
--display-name="On-call Email" \
--type=email \
--channel-labels=email_address="oncall@example.com"
# Create a Slack notification channel
gcloud alpha monitoring channels create \
--display-name="DB-Ops Slack" \
--type=slack \
--channel-labels=slack_channel="#db-alerts",slack_auth_token="xoxb-..."
For production workloads, configure escalation policies: if an alert is unacknowledged after 10 minutes, escalate to a secondary responder or broadcast to a wider team. This is handled in the alerting policy's notificationChannels and the associated incident management system (e.g., PagerDuty).
Building Effective Dashboards
Pre-Built Cloud SQL Dashboards
Google Cloud automatically provides curated dashboards for Cloud SQL. In the Monitoring console, navigate to Dashboards → Cloud SQL. You'll find tiles for CPU, memory, disk, network, and per-engine metrics already arranged. These are excellent starting points but are generic—they show all instances aggregated. For production observability, you'll want custom dashboards focused on your specific workloads.
Creating a Custom Dashboard via Console
In Cloud Monitoring, go to Dashboards → Create Dashboard. Add widgets: line charts, heatmaps, scorecards, text annotations, and tables. Each widget can contain MQL queries, giving you complete control over visualization. A practical custom dashboard for a production Cloud SQL deployment typically includes:
- Top-level scorecards: Instance status (RUNNING), current CPU %, disk %, connection count.
- Time-series charts: CPU, memory, disk IOPS over the past 7 days.
- Database engine panels: Buffer pool hit ratio, replication lag, transaction rate.
- Log correlation: Counts of error logs or slow queries overlaid with performance metrics.
Creating Dashboards Programmatically (JSON + gcloud)
For infrastructure-as-code workflows, define dashboards as JSON and deploy them via gcloud or the API. Here is a complete dashboard definition with multiple widgets:
{
"displayName": "Production Cloud SQL Overview",
"dashboardFilters": [
{
"filterType": "RESOURCE_LABEL",
"labelKey": "database_id",
"stringValue": "prod-primary-instance"
}
],
"mosaicLayout": {
"columns": 12,
"tiles": [
{
"title": "CPU Utilization (last 1h)",
"widget": {
"scorecard": {
"timeSeriesQuery": {
"timeSeriesQueryLanguage": "fetch cloudsql_database::cloudsql.googleapis.com/database/cpu/utilization | align mean_align(5m) | every 5m | window 1h | group_by [], mean(val())"
},
"thresholds": [
{ "label": "Low (<50%)", "value": 0.5, "color": "GREEN" },
{ "label": "Medium (50-80%)", "value": 0.8, "color": "YELLOW" },
{ "label": "High (>80%)", "value": 1.0, "color": "RED" }
]
}
},
"xPos": 0, "yPos": 0,
"width": 4, "height": 4
},
{
"title": "Disk Utilization Trend (7 days)",
"widget": {
"xyChart": {
"chartOptions": {
"mode": "LINE",
"showLegend": true
},
"dataSets": [
{
"timeSeriesQuery": {
"timeSeriesQueryLanguage": "fetch cloudsql_database::cloudsql.googleapis.com/database/disk/utilization | align mean_align(1h) | every 1h | window 7d"
}
}
]
}
},
"xPos": 4, "yPos": 0,
"width": 8, "height": 4
},
{
"title": "Active Connections",
"widget": {
"xyChart": {
"chartOptions": { "mode": "LINE" },
"dataSets": [
{
"timeSeriesQuery": {
"timeSeriesQueryLanguage": "fetch cloudsql_database::cloudsql.googleapis.com/database/postgresql/num_backends | align mean_align(1m) | every 1m | window 6h"
}
}
]
}
},
"xPos": 0, "yPos": 4,
"width": 6, "height": 4
},
{
"title": "Transaction Rate (commits/sec)",
"widget": {
"xyChart": {
"chartOptions": { "mode": "LINE" },
"dataSets": [
{
"timeSeriesQuery": {
"timeSeriesQueryLanguage": "fetch cloudsql_database::cloudsql.googleapis.com/database/postgresql/xact_commit | align rate(1m) | every 1m | window 6h"
}
}
]
}
},
"xPos": 6, "yPos": 4,
"width": 6, "height": 4
},
{
"title": "Replication Lag (seconds)",
"widget": {
"xyChart": {
"chartOptions": { "mode": "LINE" },
"dataSets": [
{
"timeSeriesQuery": {
"timeSeriesQueryLanguage": "fetch cloudsql_database::cloudsql.googleapis.com/database/mysql/Seconds_Behind_Master | align max_align(1m) | every 1m | window 1h"
}
}
]
}
},
"xPos": 0, "yPos": 8,
"width": 12, "height": 4
}
]
}
}
Deploy this dashboard with:
gcloud monitoring dashboards create --config=dashboard.json
Integrating Cloud SQL Logs into Dashboards
Dashboards can also display log-based metrics. For instance, you might create a widget that counts slow queries (extracted from Cloud Logging) and overlays them with CPU spikes. First, create the log-based metric as shown earlier, then query it in MQL:
# In a dashboard widget, reference the log-based metric
fetch cloudsql_database::logging/user/slow_query_count
| align rate(1h)
| every 1h
| window 24h
This correlation helps you distinguish between CPU spikes caused by traffic surges versus those caused by poorly optimized queries.
Best Practices for Cloud SQL Monitoring
1. Define and Track SLOs
Service Level Objectives turn raw metrics into user-centric targets. For Cloud SQL, typical SLOs include:
- Availability: Percentage of time the instance is RUNNING (target: 99.9% or 99.99%).
- Latency: p99 query response time under 50ms for OLTP workloads.
- Durability: Zero data loss events, tracked via replication health and backup success.
Use Cloud Monitoring's SLO tracking features or compute burn rate alerts in MQL:
# Burn rate alert: if error rate over 1h burns through 30-day error budget faster than 10x
fetch cloudsql_database::custom/error_rate
| align rate(1h)
| every 1h
| condition val() > 0.01 * 10 # 10% error budget consumption in 1h => 10x burn rate
2. Separate Signal from Noise
Not every metric deserves an alert. Reserve alerts for conditions that require immediate human action. For informational trends (e.g., storage growth at 60%), use dashboard annotations or weekly reports. Alert fatigue is a real operational risk—engineers learn to ignore noisy alerts, and then miss critical ones.
3. Use Composite Conditions
A single metric spike can be transient and benign. Combine conditions to reduce false positives. For example, alert on high CPU only if active connections are also elevated, suggesting a traffic-driven spike rather than a background maintenance task:
# Composite MQL: CPU > 80% AND connections > 100
fetch cloudsql_database::cloudsql.googleapis.com/database/cpu/utilization
| align mean_align(5m) | every 5m
| map val() >= 0.80 => 1, val() < 0.80 => 0
| join(
fetch cloudsql_database::cloudsql.googleapis.com/database/postgresql/num_backends
| align mean_align(5m) | every 5m
| map val() >= 100 => 1, val() < 100 => 0
)
| map (val(0) + val(1)) == 2 => 1, (val(0) + val(1)) < 2 => 0
| condition val() == 1
4. Monitor Replication and Failover Health
If you use Cloud SQL high-availability (HA) configuration with a regional primary and a standby in another zone, monitor replication continuity. Failover events can cause brief disconnections; track them via the cloudsql.googleapis.com/database/ha/state metric and alert if the instance is in a degraded HA state for more than a few minutes.
5. Instrument the Application Side Too
Cloud SQL metrics show you the database perspective, but the application sees connection latency, transaction duration, and error rates. Use client-side instrumentation (OpenTelemetry, SQL commenters like sqlcommenter) to inject application context into query logs, then correlate database metrics with application traces in Cloud Trace or your APM tool.
# Example: Using sqlcommenter with Python SQLAlchemy to tag queries with caller info
# pip install sqlalchemy sqlcommenter
from sqlalchemy import create_engine
from sqlcommenter.sqlalchemy import SqlCommenterExtension
engine = create_engine("postgresql+psycopg2://user:pass@/db?host=/cloudsql/...")
SqlCommenterExtension.configure(engine,
application_name="order-service",
environment="production")
# Queries now carry tags like /* application=order-service,env=production */
6. Automate Response with Cloud Functions
For known remediation steps, trigger automatic responses via Pub/Sub notification channels and Cloud Functions. For instance, when a high-connection alert fires, automatically log snapshot diagnostics:
# Cloud Function triggered by Pub/Sub alert notification
import base64
import json
from google.cloud import logging_v3
def auto_diagnostics(event, context):
alert = json.loads(base64.b64decode(event['data']).decode('utf-8'))
instance_id = alert['metric']['labels']['database_id']
# Insert diagnostic query into Cloud Logging for later analysis
logging_client = logging_v3.LoggingServiceV2Client()
# ... code to fetch and log connection details, lock stats, etc.
print(f"Auto-diagnostics triggered for {instance_id}")
7. Retain and Analyze Long-Term Metrics
Cloud Monitoring retains 6-month metrics for standard alignment windows, but high-resolution (1-second) data expires after roughly 6 weeks. For capacity planning and seasonal trend analysis, export metrics to BigQuery or Cloud Storage via scheduled exports. This lets you run SQL analytics over years of database performance data:
# Example: Schedule a Cloud Scheduler job to export metrics to BigQuery weekly
gcloud scheduler jobs create pubsub export-cloudsql-metrics \
--schedule="0 0 * * 1" \
--topic=metric-export-trigger \
--message-body='{"export_window":"7d","destination":"bigquery"}'
8. Test Your Alerting Pipeline Regularly
Conduct "fire drills" where you intentionally trigger an alert (e.g., by running a CPU-intensive query on a test instance) and verify that the notification reaches responders within the expected time window. Document which alerts map to which runbooks, and keep those runbooks updated in your incident management system.
9. Use Infrastructure as Code for Monitoring Configuration
Treat alerting policies, dashboards, and log-based metrics as code. Store YAML/JSON definitions in version control, deploy via CI/CD, and enforce review gates. This prevents configuration drift and ensures that monitoring evolves alongside your database topology changes:
# Example CI/CD snippet (cloudbuild.yaml) to deploy alerting policies
steps:
- name: 'gcr.io/google.com/cloudsdktool/google-cloud-cli'
entrypoint: bash
args:
- '-c'
- |
for f in monitoring/alerts/*.yaml; do
gcloud alpha monitoring policies create --policy-from-file="$f"
done
gcloud monitoring dashboards create --config=monitoring/dashboards/prod-db.json
Conclusion
Monitoring Cloud SQL is not a one-time setup task—it is an evolving practice that matures alongside your application. Start by understanding the rich set of built-in metrics Google Cloud provides at no extra instrumentation cost. Then layer on alerting policies that focus on actionable conditions: sustained high CPU, disk fullness, connection exhaustion, replication lag, and SLO burn rate. Build dashboards that tell a coherent story, from infrastructure health down to database engine internals, and correlate them with application-side telemetry. Apply the best practices outlined here—composite alert conditions, automated diagnostics, infrastructure-as-code, and regular fire drills—to turn your monitoring from a passive data collector into an active reliability engine. With these foundations in place, you'll catch issues early, reduce MTTR, and keep your data tier reliably serving users at scale.