WordPress Database Connection Failed: Safely Rotate MySQL/MariaDB Credentials

2026 maintenance note: Error establishing a database connection is a symptom, not proof that a password is wrong. Diagnose with read-only checks before deciding to rotate credentials. This runbook is for authorized site administrators; for managed databases, prefer the provider's control plane and procedure.

First Separate the Two Changes

The database credential and the WordPress configuration are two states that must be kept deliberately aligned:

LayerResponsibilityTypical locationRollback object
MySQL/MariaDBAuthenticate an exact 'user'@'host' accountDatabase or managed control planePrevious or secondary account credential
WordPressSubmit connection parameters to the databasewp-config.php, environment, or secret managerPrevious configuration version

Updating DB_PASSWORD does not change the database password; changing it in the database does not update WordPress. DB_PASSWORD should belong to a dedicated least-privilege application user—not database root or a remote administrator.

Before the Change: Create a Recovery Point

  1. Identify the site, database instance, WordPress root, owners, and maintenance window. State the expected impact and pause deployments, queues, and scheduled tasks that write to the database.
  2. Use an established, restore-tested process to take a database backup or managed snapshot. Confirm encryption, retention, and the recovery owner. Never put an unencrypted SQL dump in the web root.
  3. Locate the configuration actually loaded. wp-config.php may be one directory above WordPress, or it may only read environment variables or container secrets.
  4. Back up the configuration to a restricted location outside the web root and check PHP syntax first:
config_path="$(wp config path)"
umask 077
cp -- "$config_path" '/secure/backup/wp-config.php.before-rotation'
php -l "$config_path"

The backup still contains the existing secret. Protect it as credential material and destroy it under the retention policy. If the example path does not fit the system, stop and use the managed platform or deployment backup mechanism; do not improvise a publicly readable copy.

Before the Change: Test the Current Connection Read-Only

Inspect only non-secret settings. Do not run wp config list, read DB_PASSWORD, or paste it anywhere: these actions can print the secret into a terminal, session recording, or ticket.

wp config path
wp config has DB_PASSWORD
wp config get DB_NAME --type=constant
wp config get DB_USER --type=constant
wp config get DB_HOST --type=constant

Then use the configuration WordPress actually loads for a minimal read-only query:

wp db query 'SELECT 1;' --skip-column-names --quiet

To separate WordPress from a client connection, let the client prompt interactively. Never attach a password value to -p or --password:

mysql --user='WP_APP_USER' --password 
  --host='DB_HOST' --port=3306 
  --database='WP_DATABASE' --execute='SELECT 1;'

If the provider explicitly requires a Unix socket, test its supplied path separately:

mysql --user='WP_APP_USER' --password 
  --socket='/path/from-provider/mysql.sock' 
  --database='WP_DATABASE' --execute='SELECT 1;'
  • Both tests succeed: the present credential works. Do not rotate because of one generic error; investigate intermittent networking, resource exhaustion, or the application layer.
  • The client succeeds but WP-CLI fails: inspect the actual config file, PHP parsing, environment variables, container secret, PHP database driver, and runtime user.
  • Both fail: classify the database service, network, endpoint, account, or credential problem first. If the current password is unknown, do not blindly reset the production account.

Diagnose by Error Class, Not by Guessing a Password

SymptomCheck firstStop condition
Access deniedExact username, client source host, password, lock/expiry, authentication pluginDo not create 'user'@'%' or switch to root as a bypass
Connection refused / timeoutDatabase process, listener, port, firewall, security group, proxy, routingDo not open a database port to the world as a “test”
Socket file missingWhether DB_HOST selects a socket; PHP and client socket pathsDo not link an absent path to an arbitrary socket
Unknown databaseDB_NAME, instance/tenant, case, deployment environmentDo not create an empty database over the problem
DNS or TLS errorManaged endpoint, DNS, CA, certificate name, client TLS capabilityDo not disable certificate validation or downgrade transport
Client plugin unsupportedServer auth plugin; PHP/mysqli/mysqlnd or proxy versionDo not globally re-enable a legacy auth plugin

localhost and 127.0.0.1 need not be equivalent: the former often selects a Unix socket, while the latter normally uses TCP. Remote endpoints can also require a port, DNS, proxy, or verified TLS. WordPress's official `DB_HOST` guidance documents host, port, and socket forms, but the actual value must come from the provider or deployment configuration.

Verify the Exact Account and Least Privilege

A MySQL/MariaDB account is identified by username and client host. The database may see a web node, container subnet, or proxy as the source—not the browser user. Connect with an existing controlled administrator account, not remote root; for remote access, add the certificate-verification options required by the provider:

MYSQL_HISTFILE=/dev/null mysql 
  --user='DB_ADMIN_USER' --password 
  --host='DB_ADMIN_ENDPOINT'

In a controlled session that neither records nor shares raw output, inspect only identity, version, existing plugin, and grants. Redact host, schema, and account names before placing output in a ticket, and never query or copy password hashes:

SELECT CURRENT_USER(), @@version, @@version_comment;
SHOW GRANTS FOR 'WP_APP_USER'@'WP_APP_HOST';
SELECT User, Host, plugin FROM mysql.user WHERE User = 'WP_APP_USER';

Confirm that the application user retains only its existing permissions on the WordPress database. A password incident is not a privilege-redesign window: do not grant global ALL privileges, create a wildcard-source administrator, or edit system account tables directly.

Choose a Version-Verified Rotation Path

Use this preference order:

  1. Managed control plane: if the provider offers credential rotation, secret versions, or blue-green cutover, use that procedure; the SQL templates may not apply.
  2. MySQL 8.0.14+ dual passwords: use only when the exact server version, authentication plugin, and administrator privileges support RETAIN CURRENT PASSWORD/DISCARD OLD PASSWORD. The old password temporarily remains a secondary credential for application rollback.
  3. Single-password cutover: MariaDB, older MySQL, external authentication plugins, and systems without dual passwords require a maintenance window and close coordination. Rehearse against the same version outside production.

The following are syntax templates, not real secrets. Substitute values from the secret manager only in an approved session with client history disabled, no --syslog/--log-raw, no terminal recording, and a compatible server-audit policy.

MySQL 8.0.14+ dual-password template; first confirm from official documentation that EXISTING_AUTH_PLUGIN is the account's current supported plugin:

ALTER USER 'WP_APP_USER'@'WP_APP_HOST'
  IDENTIFIED WITH EXISTING_AUTH_PLUGIN
  BY 'REPLACE_WITH_NEW_SECRET'
  RETAIN CURRENT PASSWORD;

Without dual passwords, a password-based plugin on MySQL 8.x can use this template; it immediately invalidates the old password:

ALTER USER 'WP_APP_USER'@'WP_APP_HOST'
  IDENTIFIED WITH EXISTING_AUTH_PLUGIN
  BY 'REPLACE_WITH_NEW_SECRET';

MariaDB authentication syntax and plugin behavior differ. Consider this template only when the target version's official `ALTER USER` documentation confirms that the account uses a password-storing plugin; external authentication such as unix_socket, PAM, or GSSAPI cannot be handled this way:

ALTER USER 'WP_APP_USER'@'WP_APP_HOST'
  IDENTIFIED BY 'REPLACE_WITH_NEW_SECRET';

If the version, plugin, or managed restriction is unclear, stop and escalate to the DBA/provider. Do not edit system account tables directly, grant broad privileges, or restart in a mode that skips grant checks.

Make One Bounded Change at a Time

  1. Record the baseline and rollback point without secrets. Unless the incident is a confirmed password mismatch, diagnose an unhealthy baseline before rotating.
  2. Generate and retain the new secret in an approved secret manager. Do not place it in a shell variable, process argument, chat, clipboard history, screenshot, or ticket.
  3. Select one version-matched path above and alter the exact 'WP_APP_USER'@'WP_APP_HOST' account once. Do not simultaneously change the plugin, privileges, host scope, or TLS policy.
  4. Immediately update WordPress's real configuration source. Include every process, node, or replica sharing the account in one deployment plan.
  5. Roll the runtime only if it caches an environment variable or mounted secret. Do not restart the database casually.
  6. Run read-only validation and observe the web tier, queues, and cron. On failure, enter the rollback gate rather than guessing more passwords.

Update the WordPress Side Without Leaking the Secret

A conventional wp-config.php has this structure; the placeholders are not usable credentials:

define( 'DB_NAME', 'WP_DATABASE' );
define( 'DB_USER', 'WP_APP_USER' );
define( 'DB_PASSWORD', 'REPLACE_WITH_SECRET_FROM_APPROVED_STORE' );
define( 'DB_HOST', 'DB_HOST[:PORT_OR_SOCKET]' );

If the deployment already reads from an environment or secret mount, preserve that design, for example:

define( 'DB_PASSWORD', getenv( 'WORDPRESS_DB_PASSWORD' ) );

Do not redesign secret delivery during this incident. Use a secure editor, secret manager, or deployment system for an atomic update. wp config edit can open the file, but never pass the real secret to wp config set as a command-line argument. Restore the existing owner and minimum readable mode afterward. WordPress's hardening guide recommends that only required users/services can read wp-config.php (commonly 400 or 440 where compatible), but permissions must fit the actual PHP runtime model.

Verify Before Closing the Rollback Window

Check PHP syntax, the database connection, and WordPress installation status without --debug or printing configuration:

php -l "$(wp config path)"
wp db query 'SELECT 1;' --skip-column-names --quiet
wp core is-installed --quiet

Next, request a read-only page externally and inspect sanitized PHP, web, database-proxy, queue, and cron errors. Confirm that every replica uses the new secret and no consumer is retrying the old one. Multisite and shared users require coverage of every consumer.

For MySQL 8.0.14+ dual passwords, an approved administrator may remove the secondary credential only after the observation period ends and rollback is no longer required:

ALTER USER 'WP_APP_USER'@'WP_APP_HOST'
  DISCARD OLD PASSWORD;

Repeat read-only validation afterward. A cached successful page is not proof of a database connection.

Rollback and Recovery Gates

PhaseSafe actionDo not
Database unchangedStop and correct the plan or diagnosisChange a password merely to “try it”
Dual password enabled; old credential still worksRestore the previous config/secret version, validate, then investigateRun DISCARD OLD PASSWORD first
Single password changed; application failsUse a prompted client to determine whether the database accepts the new credential; restore the old database credential and config through the approved processFlip repeatedly between two passwords
Old credential discarded or lostKeep maintenance in place and use the provider/DBA account-recovery processEnable grant-bypass mode or remote root

A rollback is itself a controlled password change and needs the same history, logging, audit, and two-person review controls. If the backup is not restorable, the account identity is unclear, or authorized administrator access is absent, stop and escalate.

Multisite, Containers, and Managed Environments

  • WordPress Multisite: a network normally shares an installation and database connection, so one credential change can affect every subsite. --url does not change the database target of wp db query.
  • Multiple WordPress instances: separate installations can share one database user. Inventory deployments and secret references before rotation; do not discover consumers by printing config values.
  • Containers/Kubernetes: change the secret source and roll every replica. Do not edit an ephemeral container that will be replaced. Confirm that old Pods, workers, and cron processes have exited.
  • Managed hosting/cloud databases: the platform defines endpoints, CAs, proxies, allowed sources, rotation APIs, and recovery. Do not bypass the control plane with generic SQL.
  • Proxies/read-write split/high availability: test the endpoint WordPress actually uses. A successful direct primary connection does not prove that the proxy, DNS, or read replica works.

Official Documentation

2011 Original Archive (Not Current Instructions)

The complete visible source_export body follows, with trailing whitespace normalized only. It records an important synchronization principle, but does not cover current secure rotation, connection paths, version differences, or rollback requirements, so it is not a standalone production runbook.

MySQL改密码, WordPress无法连接数据库


当你更改 MySQL 密码之后,也要更改 WordPress 根目录里的 wp-config.php 文件里安装时所保存的 MySQL 密码为当前的 MySQL 密码,不然密码都错误,那怎么会连接得上数据库呢。这个没有那么智能的,你不去更改,它是不会知道你改了 MySQL 数据库密码的。

Leave a Reply