[{"data":1,"prerenderedAt":1531},["ShallowReactive",2],{"blog-supabase-tenant-or-user-not-found":3,"related-supabase-tenant-or-user-not-found":1530},{"id":4,"title":5,"author":6,"body":7,"category":1513,"date":1514,"description":1515,"extension":1516,"featured":1517,"image":1518,"meta":1519,"navigation":227,"path":1520,"readTime":1521,"seo":1522,"sitemap":1523,"stem":1524,"tags":1525,"__hash__":1529},"blog\u002Fblog\u002Fsupabase-tenant-or-user-not-found.md","Fix Supabase Tenant or User Not Found (Prisma Guide)","SynchSoft Team",{"type":8,"value":9,"toc":1499},"minimark",[10,15,19,30,55,58,62,88,92,107,113,132,135,141,145,148,167,170,176,179,257,268,271,280,284,287,332,338,365,371,375,382,726,729,735,749,752,788,792,799,847,853,859,969,972,991,997,1001,1004,1030,1062,1068,1079,1086,1108,1114,1124,1149,1155,1166,1170,1173,1232,1239,1243,1389,1393,1404,1410,1414,1421,1468,1471,1485,1495],[11,12,14],"h2",{"id":13},"introduction","Introduction",[16,17,18],"p",{},"You point your app at a fresh Supabase project, run a query, and get this:",[20,21,27],"pre",{"className":22,"code":24,"language":25,"meta":26},[23],"language-text","psql: error: connection to server at \"aws-1-ap-south-1.pooler.supabase.com\" (3.111.225.200),\nport 5432 failed: FATAL:  (ENOTFOUND) tenant\u002Fuser postgres.abcdefghijklmnopqrst not found\n","text","",[28,29,24],"code",{"__ignoreMap":26},[16,31,32,33,37,38,42,43,46,47,50,51,54],{},"The ",[34,35,36],"strong",{},"Supabase tenant or user not found"," error is almost never about your password, and almost always about your ",[39,40,41],"em",{},"hostname",". This guide walks through diagnosing it properly, why ",[28,44,45],{},"db.\u003Cproject-ref>.supabase.co"," often refuses to resolve at all, how to wire the result into ",[34,48,49],{},"Prisma",", and the security gotcha that ",[28,52,53],{},"prisma db push"," leaves behind on a Supabase project.",[16,56,57],{},"It's written for the case we hit most: migrating an existing app to a new Supabase project, where every connection string is a hand-edited copy of the old one.",[11,59,61],{"id":60},"prerequisites","Prerequisites",[63,64,65,69,79,82],"ul",{},[66,67,68],"li",{},"A Supabase project (this guide assumes the free or Pro tier, no IPv4 add-on)",[66,70,71,74,75,78],{},[28,72,73],{},"psql"," available locally — ",[28,76,77],{},"brew install libpq"," on macOS",[66,80,81],{},"Prisma 6 or 7 if you're following the ORM sections",[66,83,84,85],{},"Your database password from ",[34,86,87],{},"Dashboard → Project Settings → Database",[11,89,91],{"id":90},"why-tenant-or-user-not-found-happens","Why \"Tenant or User Not Found\" Happens",[16,93,94,95,98,99,102,103,106],{},"Supabase's connection pooler (",[34,96,97],{},"Supavisor",") is ",[39,100,101],{},"multi-tenant and regional",". Every project in a given AWS region shares one pooler hostname, and your project ref is carried in the ",[34,104,105],{},"username",", not the host:",[20,108,111],{"className":109,"code":110,"language":25,"meta":26},[23],"postgresql:\u002F\u002Fpostgres.\u003Cproject-ref>:\u003Cpassword>@aws-0-\u003Cregion>.pooler.supabase.com:6543\u002Fpostgres\n",[28,112,110],{"__ignoreMap":26},[16,114,115,116,119,120,123,124,127,128,131],{},"When Supavisor receives a connection, it looks up the tenant from that username ",[39,117,118],{},"within the region it's running in",". If your project lives in ",[28,121,122],{},"ap-southeast-2"," but you connected to the ",[28,125,126],{},"ap-south-1"," pooler, that region has genuinely never heard of your tenant — so it returns ",[28,129,130],{},"ENOTFOUND",", not an auth failure.",[16,133,134],{},"This is why the error is so misleading. It reads like a credentials problem. It's a routing problem.",[16,136,137,140],{},[34,138,139],{},"The single most common cause:"," copying an old project's connection string and swapping only the project ref, leaving the previous project's region in the host.",[11,142,144],{"id":143},"why-dbproject-refsupabaseco-wont-resolve","Why db.project-ref.supabase.co Won't Resolve",[16,146,147],{},"The obvious workaround is the direct connection string the dashboard shows:",[20,149,153],{"className":150,"code":151,"language":152,"meta":26,"style":26},"language-bash shiki shiki-themes github-dark","psql \"postgresql:\u002F\u002Fpostgres:[YOUR-PASSWORD]@db.\u003Cproject-ref>.supabase.co:5432\u002Fpostgres\"\n","bash",[28,154,155],{"__ignoreMap":26},[156,157,160,163],"span",{"class":158,"line":159},"line",1,[156,161,73],{"class":162},"svObZ",[156,164,166],{"class":165},"sU2Wk"," \"postgresql:\u002F\u002Fpostgres:[YOUR-PASSWORD]@db.\u003Cproject-ref>.supabase.co:5432\u002Fpostgres\"\n",[16,168,169],{},"On many machines that fails before it even opens a socket:",[20,171,174],{"className":172,"code":173,"language":25,"meta":26},[23],"psql: error: could not translate host name \"db.\u003Cproject-ref>.supabase.co\" to address:\nnodename nor servname provided, or not known\n",[28,175,173],{"__ignoreMap":26},[16,177,178],{},"Check the DNS records and the reason becomes obvious:",[20,180,182],{"className":150,"code":181,"language":152,"meta":26,"style":26},"dig +short AAAA db.\u003Cproject-ref>.supabase.co\n# 2406:da1c:10e4:6402:f9d4:cf88:300d:e4a5\n\ndig +short A db.\u003Cproject-ref>.supabase.co\n# (empty)\n",[28,183,184,215,222,229,251],{"__ignoreMap":26},[156,185,186,189,192,195,198,202,205,209,212],{"class":158,"line":159},[156,187,188],{"class":162},"dig",[156,190,191],{"class":165}," +short",[156,193,194],{"class":165}," AAAA",[156,196,197],{"class":165}," db.",[156,199,201],{"class":200},"snl16","\u003C",[156,203,204],{"class":165},"project-re",[156,206,208],{"class":207},"s95oV","f",[156,210,211],{"class":200},">",[156,213,214],{"class":165},".supabase.co\n",[156,216,218],{"class":158,"line":217},2,[156,219,221],{"class":220},"sAwPA","# 2406:da1c:10e4:6402:f9d4:cf88:300d:e4a5\n",[156,223,225],{"class":158,"line":224},3,[156,226,228],{"emptyLinePlaceholder":227},true,"\n",[156,230,232,234,236,239,241,243,245,247,249],{"class":158,"line":231},4,[156,233,188],{"class":162},[156,235,191],{"class":165},[156,237,238],{"class":165}," A",[156,240,197],{"class":165},[156,242,201],{"class":200},[156,244,204],{"class":165},[156,246,208],{"class":207},[156,248,211],{"class":200},[156,250,214],{"class":165},[156,252,254],{"class":158,"line":253},5,[156,255,256],{"class":220},"# (empty)\n",[16,258,259,260,263,264,267],{},"There's an ",[34,261,262],{},"AAAA record but no A record",". Direct connections to Supabase are ",[34,265,266],{},"IPv6-only"," unless you buy the IPv4 add-on. If your ISP, office network, CI runner, or Docker bridge is IPv4-only, that hostname is unreachable no matter what you put in the password field.",[16,269,270],{},"Supavisor, by contrast, is IPv4-reachable on every tier. So on an IPv4-only machine the pooler isn't just the recommended path — it's the only one.",[272,273,274],"blockquote",{},[16,275,276,279],{},[34,277,278],{},"Don't trust the AAAA record to tell you the region."," In our case the IPv6 address sat in an AWS Mumbai range while the project was actually in Sydney. Resolve the region from the pooler, not from DNS.",[11,281,283],{"id":282},"step-1-confirm-the-project-is-actually-alive","Step 1: Confirm the Project Is Actually Alive",[16,285,286],{},"Before debugging connection strings, prove the project exists. Hit the REST endpoint:",[20,288,290],{"className":150,"code":289,"language":152,"meta":26,"style":26},"curl -s -o \u002Fdev\u002Fnull -w \"%{http_code}\\n\" https:\u002F\u002F\u003Cproject-ref>.supabase.co\u002Frest\u002Fv1\u002F\n# 401\n",[28,291,292,327],{"__ignoreMap":26},[156,293,294,297,301,304,307,310,313,316,318,320,322,324],{"class":158,"line":159},[156,295,296],{"class":162},"curl",[156,298,300],{"class":299},"sDLfK"," -s",[156,302,303],{"class":299}," -o",[156,305,306],{"class":165}," \u002Fdev\u002Fnull",[156,308,309],{"class":299}," -w",[156,311,312],{"class":165}," \"%{http_code}\\n\"",[156,314,315],{"class":165}," https:\u002F\u002F",[156,317,201],{"class":200},[156,319,204],{"class":165},[156,321,208],{"class":207},[156,323,211],{"class":200},[156,325,326],{"class":165},".supabase.co\u002Frest\u002Fv1\u002F\n",[156,328,329],{"class":158,"line":217},[156,330,331],{"class":220},"# 401\n",[16,333,334,337],{},[34,335,336],{},"A 401 is the success case."," It means the API is up and rejecting you for having no key. Compare with a deleted or non-existent project:",[20,339,341],{"className":150,"code":340,"language":152,"meta":26,"style":26},"host \u003Cold-project-ref>.supabase.co\n# Host \u003Cold-project-ref>.supabase.co not found: 3(NXDOMAIN)\n",[28,342,343,360],{"__ignoreMap":26},[156,344,345,348,351,354,356,358],{"class":158,"line":159},[156,346,347],{"class":162},"host",[156,349,350],{"class":200}," \u003C",[156,352,353],{"class":165},"old-project-re",[156,355,208],{"class":207},[156,357,211],{"class":200},[156,359,214],{"class":165},[156,361,362],{"class":158,"line":217},[156,363,364],{"class":220},"# Host \u003Cold-project-ref>.supabase.co not found: 3(NXDOMAIN)\n",[16,366,367,370],{},[28,368,369],{},"NXDOMAIN"," means the project is gone — no amount of connection-string fiddling will help. This check takes two seconds and tells you which problem you actually have.",[11,372,374],{"id":373},"step-2-find-your-real-pooler-region","Step 2: Find Your Real Pooler Region",[16,376,377,378,381],{},"The reliable answer is in ",[34,379,380],{},"Dashboard → Connect → Transaction pooler",", which prints the exact string. If you'd rather not leave the terminal, you can find the region by brute force — the error is instant and unambiguous, so scanning every region takes seconds:",[20,383,385],{"className":150,"code":384,"language":152,"meta":26,"style":26},"PW='your-database-password'\nREF='your-project-ref'\n\nfor r in us-east-1 us-east-2 us-west-1 us-west-2 ca-central-1 \\\n         eu-west-1 eu-west-2 eu-west-3 eu-central-1 eu-central-2 eu-north-1 \\\n         ap-south-1 ap-southeast-1 ap-southeast-2 ap-northeast-1 ap-northeast-2 sa-east-1; do\n  for p in aws-0 aws-1; do\n    ( out=$(PGCONNECT_TIMEOUT=6 psql \\\n        \"postgresql:\u002F\u002Fpostgres.$REF:$PW@$p-$r.pooler.supabase.com:5432\u002Fpostgres\" \\\n        -tAc \"select current_user\" 2>&1 | head -1)\n      case \"$out\" in\n        postgres*)      echo \"*** HIT $p-$r\" ;;\n        *\"not found\"*)  : ;;\n        *)              echo \"?? $p-$r => $(echo \"$out\" | cut -c1-80)\" ;;\n      esac ) &\n  done\ndone\nwait\n",[28,386,387,398,408,412,441,463,490,511,532,564,588,606,636,654,699,708,714,720],{"__ignoreMap":26},[156,388,389,392,395],{"class":158,"line":159},[156,390,391],{"class":207},"PW",[156,393,394],{"class":200},"=",[156,396,397],{"class":165},"'your-database-password'\n",[156,399,400,403,405],{"class":158,"line":217},[156,401,402],{"class":207},"REF",[156,404,394],{"class":200},[156,406,407],{"class":165},"'your-project-ref'\n",[156,409,410],{"class":158,"line":224},[156,411,228],{"emptyLinePlaceholder":227},[156,413,414,417,420,423,426,429,432,435,438],{"class":158,"line":231},[156,415,416],{"class":200},"for",[156,418,419],{"class":207}," r ",[156,421,422],{"class":200},"in",[156,424,425],{"class":165}," us-east-1",[156,427,428],{"class":165}," us-east-2",[156,430,431],{"class":165}," us-west-1",[156,433,434],{"class":165}," us-west-2",[156,436,437],{"class":165}," ca-central-1",[156,439,440],{"class":207}," \\\n",[156,442,443,446,449,452,455,458,461],{"class":158,"line":253},[156,444,445],{"class":165},"         eu-west-1",[156,447,448],{"class":165}," eu-west-2",[156,450,451],{"class":165}," eu-west-3",[156,453,454],{"class":165}," eu-central-1",[156,456,457],{"class":165}," eu-central-2",[156,459,460],{"class":165}," eu-north-1",[156,462,440],{"class":207},[156,464,466,469,472,475,478,481,484,487],{"class":158,"line":465},6,[156,467,468],{"class":165},"         ap-south-1",[156,470,471],{"class":165}," ap-southeast-1",[156,473,474],{"class":165}," ap-southeast-2",[156,476,477],{"class":165}," ap-northeast-1",[156,479,480],{"class":165}," ap-northeast-2",[156,482,483],{"class":165}," sa-east-1",[156,485,486],{"class":207},"; ",[156,488,489],{"class":200},"do\n",[156,491,493,496,499,501,504,507,509],{"class":158,"line":492},7,[156,494,495],{"class":200},"  for",[156,497,498],{"class":207}," p ",[156,500,422],{"class":200},[156,502,503],{"class":165}," aws-0",[156,505,506],{"class":165}," aws-1",[156,508,486],{"class":207},[156,510,489],{"class":200},[156,512,514,517,519,522,524,527,530],{"class":158,"line":513},8,[156,515,516],{"class":207},"    ( out",[156,518,394],{"class":200},[156,520,521],{"class":207},"$(PGCONNECT_TIMEOUT",[156,523,394],{"class":200},[156,525,526],{"class":165},"6",[156,528,529],{"class":162}," psql",[156,531,440],{"class":299},[156,533,535,538,541,544,547,550,553,556,559,562],{"class":158,"line":534},9,[156,536,537],{"class":165},"        \"postgresql:\u002F\u002Fpostgres.",[156,539,540],{"class":207},"$REF",[156,542,543],{"class":165},":",[156,545,546],{"class":207},"$PW",[156,548,549],{"class":165},"@",[156,551,552],{"class":207},"$p",[156,554,555],{"class":165},"-",[156,557,558],{"class":207},"$r",[156,560,561],{"class":165},".pooler.supabase.com:5432\u002Fpostgres\"",[156,563,440],{"class":299},[156,565,567,570,573,576,579,582,585],{"class":158,"line":566},10,[156,568,569],{"class":299},"        -tAc",[156,571,572],{"class":165}," \"select current_user\"",[156,574,575],{"class":200}," 2>&1",[156,577,578],{"class":200}," |",[156,580,581],{"class":162}," head",[156,583,584],{"class":299}," -1",[156,586,587],{"class":207},")\n",[156,589,591,594,597,600,603],{"class":158,"line":590},11,[156,592,593],{"class":200},"      case",[156,595,596],{"class":165}," \"",[156,598,599],{"class":207},"$out",[156,601,602],{"class":165},"\"",[156,604,605],{"class":200}," in\n",[156,607,609,613,616,619,622,625,627,629,631,633],{"class":158,"line":608},12,[156,610,612],{"class":611},"sns5M","        postgres",[156,614,615],{"class":200},"*",[156,617,618],{"class":200},")",[156,620,621],{"class":299},"      echo",[156,623,624],{"class":165}," \"*** HIT ",[156,626,552],{"class":207},[156,628,555],{"class":165},[156,630,558],{"class":207},[156,632,602],{"class":165},[156,634,635],{"class":207}," ;;\n",[156,637,639,642,645,647,649,652],{"class":158,"line":638},13,[156,640,641],{"class":200},"        *",[156,643,644],{"class":165},"\"not found\"",[156,646,615],{"class":200},[156,648,618],{"class":200},[156,650,651],{"class":299},"  :",[156,653,635],{"class":207},[156,655,657,660,663,666,668,670,672,675,678,680,682,685,688,691,694,697],{"class":158,"line":656},14,[156,658,659],{"class":200},"        *)",[156,661,662],{"class":299},"              echo",[156,664,665],{"class":165}," \"?? ",[156,667,552],{"class":207},[156,669,555],{"class":165},[156,671,558],{"class":207},[156,673,674],{"class":165}," => $(",[156,676,677],{"class":299},"echo",[156,679,596],{"class":165},[156,681,599],{"class":207},[156,683,684],{"class":165},"\" ",[156,686,687],{"class":200},"|",[156,689,690],{"class":162}," cut",[156,692,693],{"class":299}," -c1-80",[156,695,696],{"class":165},")\"",[156,698,635],{"class":207},[156,700,702,705],{"class":158,"line":701},15,[156,703,704],{"class":200},"      esac",[156,706,707],{"class":207}," ) &\n",[156,709,711],{"class":158,"line":710},16,[156,712,713],{"class":200},"  done\n",[156,715,717],{"class":158,"line":716},17,[156,718,719],{"class":200},"done\n",[156,721,723],{"class":158,"line":722},18,[156,724,725],{"class":299},"wait\n",[16,727,728],{},"Output:",[20,730,733],{"className":731,"code":732,"language":25,"meta":26},[23],"*** HIT aws-0-ap-southeast-2\n",[28,734,732],{"__ignoreMap":26},[16,736,737,738,741,742,745,746,748],{},"Note the ",[28,739,740],{},"aws-0"," \u002F ",[28,743,744],{},"aws-1"," prefix — regions have more than one pooler cluster, and the prefix is part of the hostname. Guessing the region right but the prefix wrong produces the identical ",[28,747,130],{}," error.",[16,750,751],{},"Reading the password from your environment rather than typing it inline keeps it out of your shell history:",[20,753,755],{"className":150,"code":754,"language":152,"meta":26,"style":26},"PW=$(grep '^DIRECT_URL=' .env | sed -E 's#.*:\u002F\u002F[^:]+:([^@]+)@.*#\\1#')\n",[28,756,757],{"__ignoreMap":26},[156,758,759,761,763,766,769,772,775,777,780,783,786],{"class":158,"line":159},[156,760,391],{"class":207},[156,762,394],{"class":200},[156,764,765],{"class":207},"$(",[156,767,768],{"class":162},"grep",[156,770,771],{"class":165}," '^DIRECT_URL='",[156,773,774],{"class":165}," .env",[156,776,578],{"class":200},[156,778,779],{"class":162}," sed",[156,781,782],{"class":299}," -E",[156,784,785],{"class":165}," 's#.*:\u002F\u002F[^:]+:([^@]+)@.*#\\1#'",[156,787,587],{"class":207},[11,789,791],{"id":790},"step-3-configure-prisma-for-the-supabase-pooler","Step 3: Configure Prisma for the Supabase Pooler",[16,793,794,795,798],{},"Prisma needs ",[34,796,797],{},"two"," URLs against Supabase, because migrations and queries want different pooling behaviour:",[20,800,802],{"className":150,"code":801,"language":152,"meta":26,"style":26},"# .env\n\n# Transaction mode (6543) — for application queries\nDATABASE_URL=\"postgresql:\u002F\u002Fpostgres.\u003Cref>:\u003Cpassword>@aws-0-\u003Cregion>.pooler.supabase.com:6543\u002Fpostgres?pgbouncer=true\"\n\n# Session mode (5432) — for migrations and DDL\nDIRECT_URL=\"postgresql:\u002F\u002Fpostgres.\u003Cref>:\u003Cpassword>@aws-0-\u003Cregion>.pooler.supabase.com:5432\u002Fpostgres\"\n",[28,803,804,809,813,818,828,832,837],{"__ignoreMap":26},[156,805,806],{"class":158,"line":159},[156,807,808],{"class":220},"# .env\n",[156,810,811],{"class":158,"line":217},[156,812,228],{"emptyLinePlaceholder":227},[156,814,815],{"class":158,"line":224},[156,816,817],{"class":220},"# Transaction mode (6543) — for application queries\n",[156,819,820,823,825],{"class":158,"line":231},[156,821,822],{"class":207},"DATABASE_URL",[156,824,394],{"class":200},[156,826,827],{"class":165},"\"postgresql:\u002F\u002Fpostgres.\u003Cref>:\u003Cpassword>@aws-0-\u003Cregion>.pooler.supabase.com:6543\u002Fpostgres?pgbouncer=true\"\n",[156,829,830],{"class":158,"line":253},[156,831,228],{"emptyLinePlaceholder":227},[156,833,834],{"class":158,"line":465},[156,835,836],{"class":220},"# Session mode (5432) — for migrations and DDL\n",[156,838,839,842,844],{"class":158,"line":492},[156,840,841],{"class":207},"DIRECT_URL",[156,843,394],{"class":200},[156,845,846],{"class":165},"\"postgresql:\u002F\u002Fpostgres.\u003Cref>:\u003Cpassword>@aws-0-\u003Cregion>.pooler.supabase.com:5432\u002Fpostgres\"\n",[16,848,32,849,852],{},[28,850,851],{},"?pgbouncer=true"," flag matters: it tells Prisma to stop using prepared statements, which transaction-mode pooling cannot support.",[16,854,855,856,543],{},"In Prisma 7, point the CLI at the direct URL via ",[28,857,858],{},"prisma.config.ts",[20,860,864],{"className":861,"code":862,"language":863,"meta":26,"style":26},"language-typescript shiki shiki-themes github-dark","import 'dotenv\u002Fconfig'\nimport { defineConfig, env } from 'prisma\u002Fconfig'\n\nexport default defineConfig({\n  earlyAccess: true,\n  schema: 'prisma\u002Fschema.prisma',\n  migrations: { path: 'prisma\u002Fmigrations' },\n  datasource: {\n    url: env('DIRECT_URL'),\n  },\n})\n","typescript",[28,865,866,874,887,891,905,916,926,937,942,959,964],{"__ignoreMap":26},[156,867,868,871],{"class":158,"line":159},[156,869,870],{"class":200},"import",[156,872,873],{"class":165}," 'dotenv\u002Fconfig'\n",[156,875,876,878,881,884],{"class":158,"line":217},[156,877,870],{"class":200},[156,879,880],{"class":207}," { defineConfig, env } ",[156,882,883],{"class":200},"from",[156,885,886],{"class":165}," 'prisma\u002Fconfig'\n",[156,888,889],{"class":158,"line":224},[156,890,228],{"emptyLinePlaceholder":227},[156,892,893,896,899,902],{"class":158,"line":231},[156,894,895],{"class":200},"export",[156,897,898],{"class":200}," default",[156,900,901],{"class":162}," defineConfig",[156,903,904],{"class":207},"({\n",[156,906,907,910,913],{"class":158,"line":253},[156,908,909],{"class":207},"  earlyAccess: ",[156,911,912],{"class":299},"true",[156,914,915],{"class":207},",\n",[156,917,918,921,924],{"class":158,"line":465},[156,919,920],{"class":207},"  schema: ",[156,922,923],{"class":165},"'prisma\u002Fschema.prisma'",[156,925,915],{"class":207},[156,927,928,931,934],{"class":158,"line":492},[156,929,930],{"class":207},"  migrations: { path: ",[156,932,933],{"class":165},"'prisma\u002Fmigrations'",[156,935,936],{"class":207}," },\n",[156,938,939],{"class":158,"line":513},[156,940,941],{"class":207},"  datasource: {\n",[156,943,944,947,950,953,956],{"class":158,"line":534},[156,945,946],{"class":207},"    url: ",[156,948,949],{"class":162},"env",[156,951,952],{"class":207},"(",[156,954,955],{"class":165},"'DIRECT_URL'",[156,957,958],{"class":207},"),\n",[156,960,961],{"class":158,"line":566},[156,962,963],{"class":207},"  },\n",[156,965,966],{"class":158,"line":590},[156,967,968],{"class":207},"})\n",[16,970,971],{},"Then push your schema:",[20,973,975],{"className":150,"code":974,"language":152,"meta":26,"style":26},"npx prisma db push\n",[28,976,977],{"__ignoreMap":26},[156,978,979,982,985,988],{"class":158,"line":159},[156,980,981],{"class":162},"npx",[156,983,984],{"class":165}," prisma",[156,986,987],{"class":165}," db",[156,989,990],{"class":165}," push\n",[20,992,995],{"className":993,"code":994,"language":25,"meta":26},[23],"Datasource \"db\": PostgreSQL database \"postgres\", schema \"public\"\nat \"aws-0-ap-southeast-2.pooler.supabase.com:5432\"\n\n🚀  Your database is now in sync with your Prisma schema. Done in 18.89s\n",[28,996,994],{"__ignoreMap":26},[11,998,1000],{"id":999},"step-4-lock-down-the-tables-prisma-db-push-created","Step 4: Lock Down the Tables prisma db push Created",[16,1002,1003],{},"This is the step most migration guides skip, and it's the one that matters.",[16,1005,1006,1007,1010,1011,1014,1015,1018,1019,1029],{},"Supabase auto-enables ",[34,1008,1009],{},"Row Level Security"," on new tables in ",[28,1012,1013],{},"public",", which is good. But the ",[28,1016,1017],{},"postgres"," role that Prisma connects as carries default privileges that grant the ",[34,1020,1021,1024,1025,1028],{},[28,1022,1023],{},"anon"," and ",[28,1026,1027],{},"authenticated"," roles full DML"," on anything it creates. Check for yourself:",[20,1031,1033],{"className":150,"code":1032,"language":152,"meta":26,"style":26},"psql \"$DIRECT_URL\" -tAc \"select table_name, string_agg(distinct privilege_type,',')\n  from information_schema.role_table_grants\n  where grantee='anon' and table_schema='public' group by 1\"\n",[28,1034,1035,1052,1057],{"__ignoreMap":26},[156,1036,1037,1039,1041,1044,1046,1049],{"class":158,"line":159},[156,1038,73],{"class":162},[156,1040,596],{"class":165},[156,1042,1043],{"class":207},"$DIRECT_URL",[156,1045,602],{"class":165},[156,1047,1048],{"class":299}," -tAc",[156,1050,1051],{"class":165}," \"select table_name, string_agg(distinct privilege_type,',')\n",[156,1053,1054],{"class":158,"line":217},[156,1055,1056],{"class":165},"  from information_schema.role_table_grants\n",[156,1058,1059],{"class":158,"line":224},[156,1060,1061],{"class":165},"  where grantee='anon' and table_schema='public' group by 1\"\n",[20,1063,1066],{"className":1064,"code":1065,"language":25,"meta":26},[23],"Lead|DELETE,INSERT,REFERENCES,SELECT,TRIGGER,TRUNCATE,UPDATE\n",[28,1067,1065],{"__ignoreMap":26},[16,1069,1070,1071,1074,1075,1078],{},"Your leads table just granted ",[28,1072,1073],{},"TRUNCATE"," to the anonymous role. RLS with zero policies still blocks it today — grants and policies are two separate gates, and reads return nothing without a policy. But it means you're exactly ",[34,1076,1077],{},"one permissive policy away"," from a public data leak, on a table you never intended to expose.",[16,1080,1081,1082,1085],{},"If your app talks to Postgres through Prisma rather than ",[28,1083,1084],{},"supabase-js",", nothing needs those grants. Revoke them:",[20,1087,1091],{"className":1088,"code":1089,"language":1090,"meta":26,"style":26},"language-sql shiki shiki-themes github-dark","revoke all on all tables in schema public from anon, authenticated;\nrevoke all on all sequences in schema public from anon, authenticated;\nalter default privileges in schema public revoke all on tables from anon, authenticated;\n","sql",[28,1092,1093,1098,1103],{"__ignoreMap":26},[156,1094,1095],{"class":158,"line":159},[156,1096,1097],{},"revoke all on all tables in schema public from anon, authenticated;\n",[156,1099,1100],{"class":158,"line":217},[156,1101,1102],{},"revoke all on all sequences in schema public from anon, authenticated;\n",[156,1104,1105],{"class":158,"line":224},[156,1106,1107],{},"alter default privileges in schema public revoke all on tables from anon, authenticated;\n",[16,1109,1110,1111,1113],{},"That third line is the one that keeps this fixed — without it, the next ",[28,1112,53],{}," re-grants everything on any new table.",[16,1115,1116,1117,1119,1120,1123],{},"Prisma keeps working because the ",[28,1118,1017],{}," role has the ",[28,1121,1122],{},"BYPASSRLS"," attribute:",[20,1125,1127],{"className":150,"code":1126,"language":152,"meta":26,"style":26},"psql \"$DIRECT_URL\" -tAc \"select rolname, rolbypassrls from pg_roles\n  where rolname in ('postgres','anon','authenticated','service_role')\"\n",[28,1128,1129,1144],{"__ignoreMap":26},[156,1130,1131,1133,1135,1137,1139,1141],{"class":158,"line":159},[156,1132,73],{"class":162},[156,1134,596],{"class":165},[156,1136,1043],{"class":207},[156,1138,602],{"class":165},[156,1140,1048],{"class":299},[156,1142,1143],{"class":165}," \"select rolname, rolbypassrls from pg_roles\n",[156,1145,1146],{"class":158,"line":217},[156,1147,1148],{"class":165},"  where rolname in ('postgres','anon','authenticated','service_role')\"\n",[20,1150,1153],{"className":1151,"code":1152,"language":25,"meta":26},[23],"anon|f\nauthenticated|f\npostgres|t\nservice_role|t\n",[28,1154,1152],{"__ignoreMap":26},[272,1156,1157],{},[16,1158,1159,1165],{},[34,1160,1161,1162,1164],{},"Only do this if you're not using ",[28,1163,1084],{}," on the client."," If your frontend queries Supabase directly with the anon key, you need those grants plus properly scoped RLS policies instead.",[11,1167,1169],{"id":1168},"step-5-verify-everything-works","Step 5: Verify Everything Works",[16,1171,1172],{},"Never trust \"it built fine.\" Test both the happy path and the thing you just locked down:",[20,1174,1176],{"className":150,"code":1175,"language":152,"meta":26,"style":26},"# Prisma's connection can read\npsql \"$DIRECT_URL\" -tAc 'select count(*) from \"Lead\";'\n# 0\n\n# The anonymous role cannot\npsql \"$DIRECT_URL\" -tAc 'set role anon; select count(*) from \"Lead\";'\n# ERROR:  permission denied for table Lead\n",[28,1177,1178,1183,1198,1203,1207,1212,1227],{"__ignoreMap":26},[156,1179,1180],{"class":158,"line":159},[156,1181,1182],{"class":220},"# Prisma's connection can read\n",[156,1184,1185,1187,1189,1191,1193,1195],{"class":158,"line":217},[156,1186,73],{"class":162},[156,1188,596],{"class":165},[156,1190,1043],{"class":207},[156,1192,602],{"class":165},[156,1194,1048],{"class":299},[156,1196,1197],{"class":165}," 'select count(*) from \"Lead\";'\n",[156,1199,1200],{"class":158,"line":224},[156,1201,1202],{"class":220},"# 0\n",[156,1204,1205],{"class":158,"line":231},[156,1206,228],{"emptyLinePlaceholder":227},[156,1208,1209],{"class":158,"line":253},[156,1210,1211],{"class":220},"# The anonymous role cannot\n",[156,1213,1214,1216,1218,1220,1222,1224],{"class":158,"line":465},[156,1215,73],{"class":162},[156,1217,596],{"class":165},[156,1219,1043],{"class":207},[156,1221,602],{"class":165},[156,1223,1048],{"class":299},[156,1225,1226],{"class":165}," 'set role anon; select count(*) from \"Lead\";'\n",[156,1228,1229],{"class":158,"line":492},[156,1230,1231],{"class":220},"# ERROR:  permission denied for table Lead\n",[16,1233,1234,1235,1238],{},"Two commands, and you've confirmed the connection works ",[39,1236,1237],{},"and"," the exposure is closed.",[11,1240,1242],{"id":1241},"troubleshooting-exact-errors-and-fixes","Troubleshooting: Exact Errors and Fixes",[1244,1245,1246,1262],"table",{},[1247,1248,1249],"thead",{},[1250,1251,1252,1256,1259],"tr",{},[1253,1254,1255],"th",{},"Error",[1253,1257,1258],{},"Cause",[1253,1260,1261],{},"Fix",[1263,1264,1265,1283,1296,1309,1335,1357,1373],"tbody",{},[1250,1266,1267,1273,1280],{},[1268,1269,1270],"td",{},[28,1271,1272],{},"FATAL: (ENOTFOUND) tenant\u002Fuser postgres.\u003Cref> not found",[1268,1274,1275,1276,1279],{},"Wrong pooler region or ",[28,1277,1278],{},"aws-N"," prefix",[1268,1281,1282],{},"Scan regions (Step 2) or copy from Dashboard → Connect",[1250,1284,1285,1290,1293],{},[1268,1286,1287],{},[28,1288,1289],{},"could not translate host name \"db.\u003Cref>.supabase.co\"",[1268,1291,1292],{},"Direct host is IPv6-only, you're on IPv4",[1268,1294,1295],{},"Use the pooler, or buy the IPv4 add-on",[1250,1297,1298,1303,1306],{},[1268,1299,1300],{},[28,1301,1302],{},"Host \u003Cref>.supabase.co not found: 3(NXDOMAIN)",[1268,1304,1305],{},"Project deleted or never existed",[1268,1307,1308],{},"Check the dashboard; the ref is wrong",[1250,1310,1311,1316,1323],{},[1268,1312,1313],{},[28,1314,1315],{},"psql: error: invalid URI query parameter: \"pgbouncer\"",[1268,1317,1318,1320,1321],{},[28,1319,73],{}," rejects Prisma's ",[28,1322,851],{},[1268,1324,1325,1326,1328,1329,1331,1332,1334],{},"Use ",[28,1327,841],{}," for ",[28,1330,73],{},", ",[28,1333,822],{}," for the app",[1250,1336,1337,1342,1348],{},[1268,1338,1339],{},[28,1340,1341],{},".env:43: parse error near '\\n'",[1268,1343,1344,1347],{},[28,1345,1346],{},"source .env"," chokes on multiline values",[1268,1349,1350,1351,1353,1354],{},"Parse the key you need with ",[28,1352,768],{},", don't ",[28,1355,1356],{},"source",[1250,1358,1359,1367,1370],{},[1268,1360,1361,1364,1365],{},[28,1362,1363],{},"unknown option --skip-generate"," on ",[28,1366,53],{},[1268,1368,1369],{},"Flag removed in Prisma 7",[1268,1371,1372],{},"Drop the flag",[1250,1374,1375,1378,1384],{},[1268,1376,1377],{},"Prepared statement errors under load",[1268,1379,1380,1381,1383],{},"Missing ",[28,1382,851],{}," on port 6543",[1268,1385,1386,1387],{},"Add it to ",[28,1388,822],{},[11,1390,1392],{"id":1391},"a-note-on-free-tier-pausing","A Note on Free-Tier Pausing",[16,1394,1395,1396,1399,1400,1403],{},"Free Supabase projects pause after ",[34,1397,1398],{},"7 days without database activity"," — and it's ",[39,1401,1402],{},"database"," activity, not HTTP traffic to your site. A project that only writes on contact-form submissions will happily pause during a quiet week, and the first thing you'll notice is production 500s.",[16,1405,1406,1407,1409],{},"If that's a risk, give the database something real to do. A first-party pageview table written on each navigation is genuinely useful analytics ",[39,1408,1237],{}," keeps the project awake, without a cron job whose only purpose is faking activity.",[11,1411,1413],{"id":1412},"conclusion","Conclusion",[16,1415,1416,1417,1420],{},"The Supabase ",[34,1418,1419],{},"tenant or user not found"," error is a routing problem wearing an authentication costume. Work through it in this order and it takes minutes rather than an afternoon:",[1422,1423,1424,1433,1439,1442,1455],"ol",{},[66,1425,1426,1427,1429,1430,618],{},"Prove the project exists (",[28,1428,296],{}," the REST endpoint, expect ",[34,1431,1432],{},"401",[66,1434,1435,1436,618],{},"Check whether the direct host is IPv6-only (",[28,1437,1438],{},"dig AAAA",[66,1440,1441],{},"Find the real pooler region — the dashboard, or scan",[66,1443,1444,1445,1447,1448,1451,1452,1454],{},"Split ",[28,1446,822],{}," (6543, ",[28,1449,1450],{},"pgbouncer=true",") from ",[28,1453,841],{}," (5432)",[66,1456,1457,1458,1460,1461,1464,1465],{},"Revoke the ",[28,1459,1023],{}," grants ",[28,1462,1463],{},"db push"," left behind, and verify with ",[28,1466,1467],{},"set role anon",[16,1469,1470],{},"That last step is the one worth adding to your checklist permanently. Every schema push against Supabase quietly re-opens it on new tables unless you've altered the default privileges.",[16,1472,1473,1474,1479,1480,1484],{},"If you're building on Postgres and want the schema, RLS policies, and connection topology reviewed before they reach production, our ",[1475,1476,1478],"a",{"href":1477},"\u002Fservices\u002Fweb-development","web development team"," does exactly this work. You may also find our guide to ",[1475,1481,1483],{"href":1482},"\u002Fblog\u002Fbuilding-realtime-applications-nodejs","building real-time applications with Node.js"," useful for the layer above the database.",[16,1486,1487],{},[39,1488,1489,1490,1494],{},"Need help with Supabase, Prisma, or a Postgres migration? ",[1475,1491,1493],{"href":1492},"\u002Fcontact","Get in touch"," to discuss your project.",[1496,1497,1498],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sns5M, html code.shiki .sns5M{--shiki-default:#DBEDFF}",{"title":26,"searchDepth":217,"depth":217,"links":1500},[1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512],{"id":13,"depth":217,"text":14},{"id":60,"depth":217,"text":61},{"id":90,"depth":217,"text":91},{"id":143,"depth":217,"text":144},{"id":282,"depth":217,"text":283},{"id":373,"depth":217,"text":374},{"id":790,"depth":217,"text":791},{"id":999,"depth":217,"text":1000},{"id":1168,"depth":217,"text":1169},{"id":1241,"depth":217,"text":1242},{"id":1391,"depth":217,"text":1392},{"id":1412,"depth":217,"text":1413},"Database","2026-08-07","Fix the Supabase pooler error FATAL (ENOTFOUND) tenant\u002Fuser not found, plus the IPv6-only db host problem, connecting Prisma, and locking down anon grants.","md",false,"\u002Fblog\u002Fsupabase-tenant-or-user-not-found.webp",{},"\u002Fblog\u002Fsupabase-tenant-or-user-not-found","8 min read",{"title":5,"description":1515},{"loc":1520},"blog\u002Fsupabase-tenant-or-user-not-found",[1526,49,1527,1528],"Supabase","PostgreSQL","Connection Pooling","i1ISOVYfEZKGVpftO4ZqpIWB7OwrnI2KGXxOg0k7ubg",[],1786094761189]