Cloud SQL Proxy : l'erreur 403 quand l'API n'est pas activée
Publié le 18 août 2026
L'erreur 403 du proxy Cloud SQL dit presque toujours la même chose : l'API Cloud SQL Admin n'est pas activée sur le projet facturé, ou le compte n'a pas le rôle roles/cloudsql.client. Les deux se ressemblent à l'oeil, mais leurs libellés diffèrent, et la fin du message nomme le projet en cause. Le proxy démarre normalement dans les deux cas : le 403 n'arrive qu'à la première connexion.
Que dit exactement le message ?
Voici la session réelle, avec le proxy v2.25.2 et un projet où l'API Cloud SQL Admin n'a jamais été appelée. L'instance visée n'existe pas, et cela n'a aucune importance : le 403 tombe avant que sa question soit posée.
$ cloud-sql-proxy --quota-project mon-projet --port 5432 mon-projet:europe-west1:demo-instance
2026/08/18 20:18:25 Authorizing with OAuth2 token
2026/08/18 20:18:25 [mon-projet:europe-west1:demo-instance] Listening on 127.0.0.1:5432
2026/08/18 20:18:30 The proxy has started successfully and is ready for new connections!
2026/08/18 20:18:34 [mon-projet:europe-west1:demo-instance] failed to connect to instance: failed to get instance: refresh error: failed to get instance metadata (connection name = "mon-projet:europe-west1:demo-instance"): googleapi: Error 403: Cloud SQL Admin API has not been used in project mon-projet before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/sqladmin.googleapis.com/overview?project=mon-projet then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.Trois informations sont enfouies dans cette ligne, et ce sont les seules qui comptent. Le nom du projet, répété trois fois, est celui que Google considère comme le consommateur de l'appel, et ce n'est pas toujours celui auquel vous pensez. L'adresse d'activation est complète et cliquable telle quelle. La dernière phrase annonce un délai de propagation, et c'est elle qui fait renoncer les gens trop tôt.
Le corps de la réponse porte aussi un motif lisible par une machine, SERVICE_DISABLED, dans le champ details. C'est lui qu'il faut chercher dans un journal, pas le texte anglais qui peut changer.
Pourquoi le proxy annonce-t-il un démarrage réussi ?
Parce qu'il ne contacte pas l'API Cloud SQL Admin au démarrage. Il ouvre le port local, écrit The proxy has started successfully and is ready for new connections!, et attend. Le premier appel part quand un client se présente vraiment sur le port, et c'est à ce moment seulement que le 403 apparaît.
Ce décalage explique la plupart des heures perdues sur cette erreur. Un script de démarrage qui attend la ligne ready for new connections la voit arriver, conclut que tout va bien, et lance l'application ; l'échec surgit ensuite, du côté applicatif, sous la forme d'une connexion refusée qui ne ressemble plus du tout à un problème d'API.
Activer l'API, et combien de temps attendre
L'activation tient en une commande, et le message d'erreur donne le lien de la console pour ceux qui préfèrent cliquer.
gcloud services enable sqladmin.googleapis.com --project=mon-projet
Reste la question que la documentation laisse ouverte : combien de temps avant que le proxy accepte de fonctionner ? Le message parle de « quelques minutes ». Nous avons mesuré deux fois, le 18 août 2026, sur un projet où l'API n'avait jamais été activée, en interrogeant l'API toutes les deux secondes à partir du lancement de la commande.
$ ./mesure.sh
avant activation : HTTP 403
T0 = 18:11:11 : gcloud services enable
Operation "operations/acat.p2-...-104773e9cada" finished successfully.
commande rendue apres 6 s
t+6s : HTTP 403
t+8s : HTTP 404
PREMIER NON-403 a t+8s8 secondes à la première mesure, 6 secondes à la seconde. Le passage de 403 à 404 est le signal recherché : 404 veut dire que l'API répond et qu'elle cherche une instance nommée demo-instance, qui n'existe pas. La porte est ouverte.
Deux détails méritent d'être notés plutôt qu'oubliés. La commande gcloud services enable rend la main avant que l'activation soit effective : à la première mesure, un appel lancé immédiatement après son retour recevait encore un 403. Et deux mesures sur un projet vide un jour donné ne sont pas une garantie de service ; Google annonce « quelques minutes » et ne doit rien de plus.
Le rôle minimal, et pourquoi editor est une mauvaise réponse
Le second 403 ne parle pas d'API mais de droits, et son libellé est court au point d'être inutile. Un compte de service sans aucun rôle, sur un projet où l'API est bien activée, reçoit ceci :
$ curl -s -H "Authorization: Bearer $JETON" -H "x-goog-user-project: mon-projet" \
"https://sqladmin.googleapis.com/sql/v1beta4/projects/mon-projet/instances/demo-instance"
{
"error": {
"code": 403,
"message": "The client is not authorized to make this request.",
"errors": [
{
"message": "The client is not authorized to make this request.",
"domain": "global",
"reason": "notAuthorized"
}
]
}
}Le motif notAuthorized remplace SERVICE_DISABLED, et c'est la seule différence fiable entre les deux situations. Un seul rôle suffit à faire basculer cet appel : après un roles/cloudsql.client sur le même compte, la même requête a répondu 404, c'est-à-dire « autorisé, mais cette instance n'existe pas ».
gcloud projects add-iam-policy-binding mon-projet \
--member="serviceAccount:[email protected]" \
--role="roles/cloudsql.client"
roles/editor débloque aussi la situation, et c'est précisément le problème : il accorde l'écriture sur presque toutes les ressources du projet pour obtenir la permission cloudsql.instances.connect. La documentation des rôles Cloud SQL, consultée le 18 août 2026, décrit roles/cloudsql.client comme le rôle prévu pour la connexion, et il n'y a aucune raison d'aller plus loin pour un poste de développement.
Les erreurs qui ressemblent à ce 403
| Ce que vous voyez | Le motif | La cause réelle |
|---|---|---|
Cloud SQL Admin API has not been used in project ... | SERVICE_DISABLED | L'API n'est pas activée sur le projet consommateur |
The client is not authorized to make this request. | notAuthorized | Le compte n'a pas roles/cloudsql.client |
The Cloud SQL instance does not exist. | instanceDoesNotExist | Le nom projet:région:instance est faux, ou l'API est éteinte et aucun projet de quota n'est joint |
could not find default credentials | aucun | Ni identifiants par défaut ni --token : le proxy s'arrête avant tout appel |
La troisième ligne est la plus traître, et elle mérite son propre paragraphe. Sans projet de quota attaché aux identifiants, le même projet à l'API éteinte ne renvoie plus un 403 mais un 404 :
$ cloud-sql-proxy --port 5432 mon-projet:europe-west1:demo-instance
2026/08/18 20:18:38 The proxy has started successfully and is ready for new connections!
2026/08/18 20:18:43 [mon-projet:europe-west1:demo-instance] failed to connect to instance: failed to get instance: refresh error: failed to get instance metadata (connection name = "mon-projet:europe-west1:demo-instance"): googleapi: Error 404: The Cloud SQL instance does not exist., instanceDoesNotExistC'est le même projet, la même API éteinte, la même seconde : seul le drapeau --quota-project a disparu. Le message envoie alors chercher une faute de frappe dans le nom de l'instance, qui n'existe pas. La documentation sur le projet de quota, consultée le 18 août 2026, explique quel projet Google facture selon la nature des identifiants ; retenez surtout qu'un 404 du proxy ne prouve pas que l'instance est absente.
Kestro compose la commande du proxy officiel et remonte cette sortie telle quelle, motif compris, au lieu d'un voyant rouge sans texte ; le guide du proxy qui refuse liste les autres refus du même genre, et la comparaison avec le proxy Cloud SQL dit ce que l'un et l'autre font vraiment.
Ce qui reste
Nos deux mesures de propagation valent pour un projet neuf, sans quota particulier, un mardi d'août. Une organisation avec des contraintes de règlement, un projet sous constraints/serviceuser.services, ou une activation faite par un autre compte que le vôtre, peuvent allonger ce délai sans que rien ne le signale.
Le cas où l'API est activée sur le projet de l'instance mais éteinte sur le projet de quota reste le plus désagréable à diagnostiquer : le message nomme un projet, vous vérifiez l'autre, et tout semble en ordre des deux côtés. Lisez le nom écrit dans le message, pas celui de votre instance.
Enfin, nous n'avons pas mesuré le comportement d'un compte de service dont le rôle vient d'être retiré. Le retrait a mis chez nous plus d'une minute à se voir, et un jeton déjà émis continue de fonctionner un moment : si vous coupez un accès pour de bon, ne comptez pas sur la seconde qui suit.