How to Connect to a CloudSQL MySQL Instance with Private IP


Not sure about everyone else, I wouldn’t run my MySQL server like a website with a public IP attached. Making the instance private is good as a security approach it is a bit inconvenient when I need to connect to it from my laptop.

With Google Cloud CLI gcloud command, it’s very easy to connect to a MySQL instance if it has a public IP:

# this works if the instance is public
gcloud sql connect <instance-name> --user root

# I hoped that this works for private IP but it doesn't, not yet in June 2025
gcloud beta connect <instance-name> --user root
gcloud alpha connect <instance-name> --user root

I can spin up a VM and setup a good old SSH tunnel for this connection but I got a better idea: Run a cloud sql proxy container in my existing GKE cluster, then port forward the connection to localhost using kubectl:

# variables
POD_NAME=cloud-sql-proxy
CLOUDSQL_PORT=3306
CURRENT_PROJECT=my-google-project-id
INSTANCE=my-mysql-instance-id
REGION=australia-southeast1

# start a cloud sql proxy container as a pod in a GKE cluster
# assuming this GKE cluster has direct access to Cloud SQL instances
# also my-service-account has proper workload identity setup so it has 
# roles/cloudsql.client role, required to run cloud sql proxy
kubectl run -n default $POD_NAME --image=gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.18.0 \
          --port=$CLOUDSQL_PORT \
          --overrides='{ "spec": { "serviceAccountName": "my-service-account" } }' \
          -- \
          --private-ip \
          --address=0.0.0.0 \
          "${CURRENT_PROJECT}:${REGION}:${INSTANCE}?port=${CLOUDSQL_PORT}"

# wait until the pod is ready. It's usually instant 
kubectl wait -n default --for=condition=Ready pod/$POD_NAME

# port forwarding 3306(remote) --> 13306(local), running in background
kubectl port-forward -n default $POD_NAME 1$CLOUDSQL_PORT:$CLOUDSQL_PORT &

# grab the root password kept in a secret and then connect using it
MYSQL_PWD=$(gcloud secrets versions access latest --secret "mysql-root-password-secret") \
  mysql -h 127.0.0.1 -P "1$CLOUDSQL_PORT" -u root --ssl-mode=PREFERRED "$@"
  
# clean up: stop the port forwarding then delete the pod
pkill kubectl
kubectl delete -n default pod $POD_NAME

The above commands can be used in a script or a function. It can also provide the port forwarding for other MySQL client such as MySQL workbench, etc.

🙂