{"record":{"id":"10c3445e9d48120b","repo":"OtterMind/Chat2DB","slug":"mysql-account-listunavailable","errorCode":"mysql.account.listUnavailable","errorMessage":"mysql.account.listUnavailable","messagePattern":"mysql\\.account\\.listUnavailable","errorType":"exception","errorClass":"BusinessException","httpStatus":null,"severity":"error","filePath":"chat2db-community-server/chat2db-community-plugins/chat2db-community-mysql/src/main/java/ai/chat2db/plugin/mysql/account/MysqlAccountManager.java","lineNumber":51,"sourceCode":"            DatabaseMetaData metaData = connection.getMetaData();\n            capability.setProductName(metaData.getDatabaseProductName());\n            capability.setProductVersion(metaData.getDatabaseProductVersion());\n        } catch (SQLException e) {\n            capability.setMessage(e.getMessage());\n        }\n        capability.setCurrentUser(querySingleString(connection, SQL_SELECT_CURRENT_USER));\n        return capability;\n    }\n\n    @Override\n    public List<AccountInfo> listAccounts(Connection connection) {\n        try {\n            return queryAccounts(connection, true);\n        } catch (SQLException lockedColumnError) {\n            try {\n                return queryAccounts(connection, false);\n            } catch (SQLException e) {\n                throw new BusinessException(ERROR_KEY_ACCOUNT_LIST_UNAVAILABLE, null, e);\n            }\n        }\n    }\n\n    @Override\n    public List<String> showGrants(Connection connection, String user, String host) {\n        try {\n            return queryGrants(connection, user, host);\n        } catch (SQLException e) {\n            throw new BusinessException(ERROR_KEY_ACCOUNT_GRANTS_UNAVAILABLE, null, e);\n        }\n    }\n\n    @Override\n    public AccountPreview preview(AccountOperationRequest command) {\n        String sql = MysqlAccountSqlBuilder.buildSql(command);\n        AccountPreview preview = new AccountPreview();\n        preview.setActionType(command.getActionType());","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/OtterMind/Chat2DB/blob/5ee1e990e73fbcae1969dc554be254fedb3ab888/chat2db-community-server/chat2db-community-plugins/chat2db-community-mysql/src/main/java/ai/chat2db/plugin/mysql/account/MysqlAccountManager.java#L33-L69","documentation":"Thrown by MysqlAccountManager.listAccounts after both attempts to read the mysql.user table fail. The method first tries a query including the account_locked column; on failure it retries without that column; if that also throws SQLException it wraps the cause in BusinessException('mysql.account.listUnavailable'). It signals the connected user cannot enumerate accounts at all.","triggerScenarios":"listAccounts(connection) where queryAccounts fails both with and without the locked column: the connected user lacks SELECT on mysql.user, the server is a MySQL fork without the expected columns, the connection was dropped, or a non-MySQL server is mistakenly treated as MySQL.","commonSituations":"Connecting with a restricted application user that has no access to mysql.user; Aurora/RDS privilege restrictions; a proxy or connection-pool reset mid-query; an older MySQL (5.6) lacking the account_locked column combined with a second unrelated failure.","solutions":["Grant the connected user SELECT on mysql.user (or a broader account-read privilege appropriate to the deployment).","Inspect BusinessException.getCause() for the SQLException's SQL state/error code to pinpoint the denial.","Verify the datasource is genuine MySQL and the columns match the expected schema.","If the user must remain restricted, disable the account-listing feature for that connection and degrade gracefully."],"exampleFix":"// before\nList<AccountInfo> accounts = accountManager.listAccounts(connection);\n\n// after\nList<AccountInfo> accounts;\ntry {\n    accounts = accountManager.listAccounts(connection);\n} catch (BusinessException e) {\n    if (\"mysql.account.listUnavailable\".equals(e.getCode())) {\n        log.warn(\"Cannot list accounts: {}\", rootMessage(e.getCause()));\n        accounts = Collections.emptyList();\n    } else {\n        throw e;\n    }\n}","handlingStrategy":"try-catch","validationCode":"// Ensure the connected user can read mysql.user before enabling account listing.\nif (!accountManager.capability(connection).isAccountListReadable()) {\n    return Collections.emptyList();\n}","typeGuard":null,"tryCatchPattern":"try {\n    return accountManager.listAccounts(connection);\n} catch (BusinessException e) {\n    if (\"mysql.account.listUnavailable\".equals(e.getCode())) {\n        log.warn(\"account list unavailable: {}\", rootMessage(e.getCause()));\n        return Collections.emptyList();\n    }\n    throw e;\n}","preventionTips":["Grant SELECT on mysql.user to the inspecting account.","Check capability().isAccountListReadable() before calling listAccounts.","Inspect the wrapped SQLException for the SQL state to diagnose denial.","Degrade the UI gracefully when listing is unavailable."],"tags":["mysql","account","privilege","metadata"],"backgroundTag":null,"analyzedSha":"5ee1e990e73fbcae1969dc554be254fedb3ab888","analyzedAt":"2026-08-14T07:05:03.077Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}