Linux  ·  critical  ·  Web, PHP & databases

MySQL: "Too many connections" or "Access denied for user"

Three distinct failures with similar-looking messages: the connection limit, an authentication mismatch, and the socket not being where the client looks.

What you see

The application reports a database error. Whether it is 1040, 1045 or 2002 completely changes what to do, and the application usually hides which it was.

What is actually wrong

1040 is the connection limit, often held open by an application that never closes them. 1045 is authentication, usually a host mismatch or an auth plugin change. 2002 is the socket path.

Codes and articles

Too many connectionsERROR 1040ERROR 1045Access denied for userERROR 2002Can't connect to local MySQL server

Fixes (3)

Find what is holding the connections
Root shell30 minutesmedium riskreversible

Error 1040.

  1. Look at what is connected and in what state.

    Shell
    mysql -e "SHOW STATUS LIKE 'Threads_connected'; SHOW STATUS LIKE 'Max_used_connections'; SHOW VARIABLES LIKE 'max_connections';"mysql -e "SELECT user,host,db,command,time,state FROM information_schema.processlist ORDER BY time DESC LIMIT 20"

    A long list of connections in the Sleep state with a high time value is an application leaking connections, not a database that needs a bigger limit. Raising max_connections there just delays the same outage and adds memory pressure.

  2. Count connections by host to identify the offending application.

    Shell
    mysql -e "SELECT SUBSTRING_INDEX(host,':',1) AS h, COUNT(*) c FROM information_schema.processlist GROUP BY h ORDER BY c DESC"
  3. Fix the application — enable connection pooling with a sensible maximum, or make sure connections are closed. Persistent connections in PHP with a large FPM pool are a frequent cause.

  4. Raise the limit if the load is genuine, accounting for memory per connection.

    Shell
    mysql -e "SET GLOBAL max_connections = 300"
  5. Make it permanent and restart during a window.

    Shell
    printf '[mysqld]\nmax_connections = 300\n' | sudo tee /etc/mysql/mysql.conf.d/99-connections.cnf
  6. Note that MySQL reserves one extra connection for a SUPER user, which is how to get in when it is full.

    Shell
    mysql -u root -p --protocol=socket
Confirm it workedThreads_connected stays below the limit at peak and Max_used_connections stops climbing.
Shell
mysql -e "SHOW STATUS LIKE 'Max_used_connections%'"
If you need to undo itSET GLOBAL max_connections back to the previous value; remove the configuration file to revert permanently.
Resolve the authentication mismatch
Root shell25 minutesmedium riskreversible

Error 1045, access denied.

  1. List the accounts and the hosts they are allowed from. A user defined for 'localhost' cannot connect from '127.0.0.1' — those are different entries.

    Shell
    sudo mysql -e "SELECT user,host,plugin FROM mysql.user ORDER BY user"

    localhost means the Unix socket; 127.0.0.1 means TCP to loopback. An application configured with an IP address will be refused by a grant written for localhost, and the error gives no hint of this.

  2. Check the authentication plugin. An application with an older client library cannot use caching_sha2_password.

    Shell
    sudo mysql -e "SELECT user,host,plugin FROM mysql.user WHERE user='appuser'"
  3. Create or correct the grant for the right host.

    Shell
    sudo mysql -e "CREATE USER IF NOT EXISTS 'appuser'@'127.0.0.1' IDENTIFIED BY 'password';GRANT SELECT,INSERT,UPDATE,DELETE ON appdb.* TO 'appuser'@'127.0.0.1';FLUSH PRIVILEGES;"
  4. Grant only what the application needs. An application account with ALL PRIVILEGES on everything turns an SQL injection into a full database compromise.

  5. Test the credential exactly as the application uses it.

    Shell
    mysql -h 127.0.0.1 -u appuser -p -e 'SELECT 1'
Confirm it workedThe application connects and the grant list matches what it needs.
Shell
sudo mysql -e "SHOW GRANTS FOR 'appuser'@'127.0.0.1'"
If you need to undo itDROP USER removes an account created in error; note the previous grants before changing them.
Point the client at the right socket
Root shell20 minuteslow riskreversible

Error 2002, cannot connect to local server through socket.

  1. Confirm the server is actually running first.

    Shell
    systemctl status mysql mariadb --no-pager 2>/dev/null | head -20sudo ss -tlnp | grep 3306
  2. Find where the socket really is.

    Shell
    sudo mysqladmin variables 2>/dev/null | grep -w socketls -l /var/run/mysqld/ /run/mysqld/ /tmp/mysql.sock 2>/dev/null

    The client has a compiled-in default that frequently differs from where the packaged server puts it. That mismatch is this whole error, and it looks exactly like a stopped service.

  3. Point the client at it in the configuration rather than passing --socket every time.

    Shell
    printf '[client]\nsocket = /var/run/mysqld/mysqld.sock\n' | sudo tee /etc/mysql/conf.d/client-socket.cnf
  4. If the server will not start, read why.

    Shell
    sudo journalctl -u mysql -n 50 --no-pagersudo tail -50 /var/log/mysql/error.log
  5. A full disk is a common reason a database refuses to start with a misleading error.

    Shell
    df -h /var/lib/mysql
Confirm it workedmysql connects with no explicit socket argument.
Shell
mysql -e 'SELECT VERSION()'
If you need to undo itRemove the client configuration file to return to the default.

Where this stops. This write-up was written and checked by hand. It says what each step changes, how to confirm it worked and how to reverse it, and anything destructive is flagged before you reach it. If it does not match what your machine is doing, search the Support Centre for the exact code or message — and when something needs a person, get in touch.