phacility/phabricator · error · PhutilProxyException

Failed while trying to read schema status: the database "%s"

Error message

Failed while trying to read schema status: the database "%s" exists, but the current user ("%s") does not have permission to access it. GRANT the current user more permissions, or use a different user.

What it means

PhabricatorStorageManagementAPI::getAppliedPatches() reads the patch-status table from the 'meta_data' database; when MySQL returns an access-denied error (AphrontAccessDeniedQueryException) instead of a missing-table error, it rethrows as PhutilProxyException with this message. It means the physical database exists (so the code cannot treat it as 'not initialized'), but the connecting MySQL user lacks privileges on it. The message names the exact database and user involved.

Source

Thrown at src/infrastructure/storage/management/PhabricatorStorageManagementAPI.php:150

          'host'      => $this->host,
          'port'      => $this->port,
          'database'  => $fragment
            ? $database
            : null,
        ));
    }
    return $return;
  }

  public function getAppliedPatches() {
    try {
      $applied = queryfx_all(
        $this->getConn('meta_data'),
        'SELECT patch FROM %T',
        self::TABLE_STATUS);
      return ipull($applied, 'patch');
    } catch (AphrontAccessDeniedQueryException $ex) {
      throw new PhutilProxyException(
        pht(
          'Failed while trying to read schema status: the database "%s" '.
          'exists, but the current user ("%s") does not have permission to '.
          'access it. GRANT the current user more permissions, or use a '.
          'different user.',
          $this->getDatabaseName('meta_data'),
          $this->getUser()),
        $ex);
    } catch (AphrontQueryException $ex) {
      return null;
    }
  }

  public function getPatchDurations() {
    try {
      $rows = queryfx_all(
        $this->getConn('meta_data'),
        'SELECT patch, duration FROM %T WHERE duration IS NOT NULL',

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Run the failing command with a user holding full privileges, or grant the current one: GRANT ALL PRIVILEGES ON `<namespace>_meta_data`.* TO '<user>'@'<host>'; FLUSH PRIVILEGES; (replace <namespace> with the value shown in the message).
  2. If multiple namespaced databases exist, grant on the whole namespace pattern: GRANT ALL ON `<namespace>`\_%`.* TO ... — bin/storage databases lists every database the user needs.
  3. Verify with: SHOW GRANTS FOR CURRENT_USER(); and SELECT patch FROM <namespace>_meta_data.patch_status; using the exact user from the error message.
  4. If the user cannot be widened, reconfigure Phabricator to connect as a management-capable user (config set for the user/pass keys) and re-run.

Example fix

-- before: user sees the db but not its contents
mysql> SELECT patch FROM phabricator_meta_data.patch_status;
ERROR 1142 (42000): SELECT command denied

-- after
mysql> GRANT ALL PRIVILEGES ON `phabricator_meta_data`.* TO 'phab'@'%';
mysql> FLUSH PRIVILEGES;
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: can this user actually read patch status?
$conn = $api->getConn('meta_data');
try {
  queryfx_one($conn, 'SELECT 1 FROM %T.%T LIMIT 1',
    $api->getDatabaseName('meta_data'), 'patch_status');
} catch (AphrontAccessDeniedQueryException $ex) {
  // Fail fast with a clear message instead of a mid-workflow proxy error.
  throw new Exception('Insufficient privileges on '.$api->getDatabaseName('meta_data'));
}

Type guard

function isMetaAccessDenied(Exception $ex) {
  return $ex instanceof PhutilProxyException
    && strpos($ex->getMessage(), 'does not have permission') !== false;
}

Try / catch

try {
  $applied = $api->getAppliedPatches();
} catch (PhutilProxyException $ex) {
  if (strpos($ex->getMessage(), 'does not have permission') !== false) {
    // Stop and fix grants; do not treat as 'not initialized'.
    return $this->grantGuidance();
  }
  throw $ex;
}

Prevention

When it happens

Trigger: Running bin/storage workflows (status, upgrade, adjust, dump) or any code path calling getAppliedPatches() where the configured user can connect and can see that <namespace>_meta_data exists but has no SELECT privilege on it or its patch_status table — e.g. granted on a different namespace's databases, or granted globally but with a revoke at the database level. Note the sibling catch: any other AphrontQueryException (like missing table) returns null meaning 'not initialized'; only permission failures take this branch.

Common situations: Fresh install where GRANT statements only covered some databases; switching --namespace to one the user was never granted on; a DBA tightening privileges and dropping SELECT on the meta database; partial GRANT ... ON phabricator_meta_data.* to a differently-named database; using a monitoring/read-only user for management commands.

Related errors


AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21). Data as JSON: /api/errors/20a8d3251475ca17. Report an issue: GitHub.