"max_questions" limit not respected when running MySQL query via PHP - php

I'm using MySQL Community Server 5.5 with PHP 5.3.3 on a Windows Server 2008 platform.
I have set up per user resources limits, particularly a limit related to the queries run by a DB user within one hour. I have read this document and it is very interesting but always it doesn't work for me.
http://dev.mysql.com/doc/refman/5.5/en/user-resources.html
When I run a query via mysql command line tool (mysql.exe) the limit works properly and if the queries limit per hour was 7, after 7 queries within one hour I receive the error:
ERROR 1226 (42000): User 'user' has
exceeded the 'max_questions' resource
(current value: 7)
This above is the wanted behavior.
When I run a query via PHP (The user I have used to connect to the DB is the same above), the queries limit doesn't work: the same user via php can run all the queries it wants and without any limit. And if I come back on the mysql command line above the counter seems to be reset (even if the hour hasn't elapsed) : I can run 7 queries within an hour too.
I think this isn't the wanted behaviour. It seems that PHP resets the counter and doesn't trigger the queries limit.
PS: The 'user' owns only SELECT,INSERT,UPDATE,DELETE privileges and in the PHP code there isn't any SQL code as FLUSH USER_RESOURCES that the user 'user' couldn't have run (because RELOAD privilege isn't assigned to the user)
Thanks in advance

Check this tip,
how many users do you have in your mysql with the same name..(remember not only the name but the host where is permited to connect the user is specified in mysql ). **VERY IMPORTANT.
user#%
user#127.0.0.1
user#localhost
user#172.35.20.12
each one of them are not the same, if you have any limit rule do you like to use, so, you must assign limitations to the user#wherever you want the limintation. (all of them, if you have problems **think is your case).
Recomendation: create a specific user for WEB PHP (only one user#host must be created) , instead using a generic user with may have several users#hosts assigned.
like phpuser#'localhost' typically is enough.

I think you are doing little mistake,
Please check for the host in your mysql_connect function into php.
if your host is IP address then you need to assign the resource limit to username#yourip or username#%
If you are running through the command line then you are login from username#localhost and you have assign the limit to the same user.
Please try my above tricks and let me know if you are having problem still ?
Happy coding....

I have solved (partially) the problem.
The problem occurs only when the query including the MAX_QUERIES_PER_HOUR component includes also one of the following elements different from 0:
MAX_CONNECTIONS_PER_HOUR !=0
MAX_USER_CONNECTIONS !=0;
e.g. the following grant query won't ever cause the error message related to the queries limit achievement in PHP:
GRANT USAGE ON *.* TO 'user'#'localhost'
WITH MAX_QUERIES_PER_HOUR 20
MAX_UPDATES_PER_HOUR 10
MAX_CONNECTIONS_PER_HOUR 5
MAX_USER_CONNECTIONS 2;
Instead the following grant works correctly and MySQL applies the limits correctly.
GRANT USAGE ON *.* TO 'user'#'localhost'
WITH MAX_QUERIES_PER_HOUR 20
MAX_UPDATES_PER_HOUR 10
MAX_CONNECTIONS_PER_HOUR 0
MAX_USER_CONNECTIONS 0;
In short, when the query setting queries limit includes one of the components, MAX_CONNECTIONS_PER_HOUR and MAX_USER_CONNECTIONS different from 0, the limits related to the MAX_QUERIES_PER_HOUR and MAX_UPDATES_PER_HOUR are ignored: my PHP pages can perform all the queries they want. Otherwise the limit is understood and the message
has exceeded the 'max_questions' resource
correctly is showed when the queries limit achievement event occurs.
As I said above the problem doesn't occurs when I use the mysql command line tool. It occurs only when queries are run through PHP pages.

Related

PHP mysql persistent connection not reused ( opens more than one connection per fpm-worker )

I'm facing a really weird behaviour while testing persistent connections from php to mysql. I have a small script that looks like this:
<?php
$db = new mysqli('p:db-host','user','pass','schema');
$res = $db->query('select * from users limit 1');
print_r($res->fetch_assoc());
My setup is :
OS: CentOS 7.3
PHP/7.1.18
php-fpm
nginx/1.10.2
MySQL-5.6.30
I tried to do some requests with ab:
$ ab -c 100 -n 500 http://mysite/my_test_script.php
PHP-FPM was configured to have 150 workers ready, and i saw what i was expecting, 150 established connections to mysql, which stayed open after the ab finished. I launched ab once again, and the behaviour was still the same, 150 connections, no new connections where opened. All fine. Then i created a script which did the the same exact requests, same IP, same HTTP headers, but used curl to make the request, and BOOM i had 300 connections on mysql instead of 150. I launched the script again, i got still 300 connections. Subsequent runs of the same script didn't increase the number of connections. Did anyone ever faced anything like this? Does anyone know what could make php open more connections than needed? Am I missing something obvious?
If it's not clear what i'm asking, please comment below and i will try to better my explain problem.
P.S. I tried this with PDO too, same behaviour.
EDIT: My tests where not accurate
After further testing i noticed that my first tests where not accurate. I was in a multi-tenant environment and different connections ( different schema ) where initialized when i launched ab. In my case the php documentation was a bit missleading, it says:
PHP checks if there's already an identical persistent connection (that remained open from earlier) - and if it exists, it uses it. If it does not exist, it creates the link. An 'identical' connection is a connection that was opened to the same host, with the same username and the same password (where applicable).
http://php.net/manual/en/features.persistent-connections.php
Maybe its i obvious to everyone, I don't know, it was not for me. Passing the 4th parameter to mysqli made php consider connections not identical. Once i changed my code to something like this:
<?php
$db = new mysqli('p:db-host','user','pass');
$db->select_db('schema');
$res = $db->query('select * from users limit 1');
print_r($res->fetch_assoc());
The application started to behave as i expected, one connection per worker.

mysql replication phpmyadmin windows version

First of all let me say there are no CLEAR tutorials for how to do this on windows, I'm a programmer and have been using MySQL and PHP for years, and have never seen so many different answers when it comes to linux, and absolutely nothing for windows users.
Anyway I have been working for 2 weeks trying to solve this myself, and I am at the same place no matter what tutorial, method or whatever I try. Basically I have two MySQL Servers. One Master, and One Slave (setup through phpMyAdmin)
I have both servers online and they can see each other and are connected to each other, however when it comes to syncing under the Slave Status table in phpMyAdmin I am constantly getting errors saying tables don't exist. But they do. Now I'm not sure if I am supposed to completely import the databases from my master manually, and then it updates it or whatever (again no clear tutorials are out there for windows). Below is the table i copied from phpMyAdmin.
Slave_IO_State Waiting for master to send event
Master_Host XX.XX.XX.XX
Master_User XXXXXXXX
Master_Port 3306
Connect_Retry 60
Master_Log_File mysql-bin.000012
Read_Master_Log_Pos 1221
Relay_Log_File *servername*-relay-bin.000003
Relay_Log_Pos 253
Relay_Master_Log_File mysql-bin.000001
Slave_IO_Running Yes
Slave_SQL_Running No
Replicate_Do_DB
Replicate_Ignore_DB
Replicate_Do_Table
Replicate_Ignore_Table
Replicate_Wild_Do_Table
Replicate_Wild_Ignore_Table
Last_Errno 1146
Last_Error Error 'Table '*databasename*.*tablename*' doesn't exist' on query. Default database: '*databasename*'. Query: 'DELETE FROM *tablename* WHERE expires
Skip_Counter 0
Exec_Master_Log_Pos 107
Relay_Log_Space 211493
Until_Condition None
Until_Log_File
Until_Log_Pos 0
Master_SSL_Allowed No
Master_SSL_CA_File
Master_SSL_CA_Path
Master_SSL_Cert
Master_SSL_Cipher
Master_SSL_Key
Seconds_Behind_Master (blank but would like this setup)
I should also add that this database that supposedly has missing tables is working perfectly on the master for an active website.
Any help to point me in the right direction would be appreciated.
You want to take a full backup of the master database and load it onto your slave or manually copy them over while the master isn't doing work. When you run your CHANGE MASTER command on the slave before starting it you want to specify the first binary log file that was created after your backup was taken like this:
CHANGE MASTER TO MASTER_HOST='xx.xx.xx.xx', MASTER_PORT=3306, MASTER_USER='user', MASTER_PASSWORD='*secret*', MASTER_LOG_FILE='mysql-bin.004388', MASTER_LOG_POS = 0
The Seconds_Behind_Master will automatically show once the slave doesn't have an error.
That is all there is to it.

mysql error: exceeded the max connections per hour

I'm getting an error while running php script for Wordpress site on same domain:
Could not connect: User 'abc' has exceeded the 'max_connections_per_hour' resource (current value: 10)
What should be the limit for MySql database? Now should I connect to the database?
You exceed limit for mysql, take a look at mysql doc, and you can see this :
GRANT ALL ON customer.* TO 'francis'#'localhost'
IDENTIFIED BY 'frank'
WITH MAX_QUERIES_PER_HOUR 20
MAX_UPDATES_PER_HOUR 10
MAX_CONNECTIONS_PER_HOUR 5;
You just have to increase MAX_CONNECTIONS_PER_HOUR or to remove limit, just use this :
GRANT USAGE ON *.* TO 'francis'#'localhost' WITH MAX_CONNECTIONS_PER_HOUR 0;
To allow persistent connection on WordPress, take a look at this article (I have not tested it myself) : http://www.mydigitallife.info/using-php-mysql-persistent-connections-to-run-wordpress-blog/

Create MySQL user and database from PHP

Is there a way to create a new MySQL database, a new MySQL user and give the new user privileges on the new database all using PHP?
EDIT - should be pointed out this is run from 1 server to another, so Server A trying to install a DB/user on Server B
i've got this:
$con = mysql_connect("REMOTE.IP.ADDRESS","root","pass");
mysql_query("CREATE DATABASE ".$db."",$con)or die(mysql_error());
mysql_query("GRANT ALL ON ".$db.".* to ".$user." identified by '".$dbpass."'",$con) or die(mysql_error());
but i'm getting an error on the grant query:
"Access denied for user 'root'#'MY.REMOTE.SERVER.HOST.NAME' to database 'dbname'"
This answer has been edited several times based on new info provided by the OP
Is root actually allowed to connect to the server from the host that you are connecting from? If the error string is returning the canonical name of the server, there's a very good chance that 'localhost' is not pointing to 127.0.0.1 :
"Access denied for user
'root'#'MY.SERVER.HOST.NAME' to
database 'dbname'"
That should echo something like "Access denied for user 'root'#localhost'", not the name of the server.
Try:
$con = mysql_connect("127.0.0.1","root","pass");
Edit (After more information provided in comments)
If you are connecting from a totally different host, you have to tell MySQL user#remote_hostname_or_ip is allowed to connect, and has appropriate privileges to create a database and users.
You can do this rather easily using phpmyadmin (on the MySQL server), or a query like:
CREATE USER 'root'#'192.168.1.1' IDENTIFIED BY PASSWORD 'secret';
GRANT ALL PRIVILEGES ON * . * TO 'root'#'192.168.1.1' IDENTIFIED BY PASSWORD 'secret' WITH GRANT OPTION MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;
I would advise not naming this user 'root' , just create a user with all of the global privileges needed. In the example, I used 192.168.1.1, that could easily be a hostname, just make sure DNS is set up appropriately. Specify the host to match exactly as it appears in logs when you connect to the remote server.
You may also want to adjust limits to taste. More information on the CREATE USER syntax can be found here, GRANT here.
Edit
If using MySQL 4 - CREATE is not an option. You would just use GRANT (4.1 Docs On User Management)
Edit
If using C-Panel, just use the API. While yes, it does have its quirks, its easier to maintain stuff that uses it rather than ad-hoc work arounds. A lot of successful applications use it without issue. Like any other API, you need to stay on top of changes when using it.
I believe you'd have to create a connection (with the root user) to an existing database (like mysql) and then run the create query.
You don't see a database connect in this example for the obvious reason: it is supposed that you learned already that any database action requires connect first.
It's the way the books being written: the things from the previous lessons being omitted in the next ones. Or every chapter will be 2 times bigger and you'll never finish the book.
so yes, you need to connect to the database first, using mysql_connect().
to create a user you can use mysql GRANT query
though I am never done it from the script but from the shell only
You would need to connect to the sql server first:
$conn=#mysql_connect(DB_HOST, DB_USER, DB_PASSWORD)
or die("Err:Conn");
Then the query will execute. A lot of shared hosting servers disable the creation of databases via PHP though.

MySQL Error "Too many connections"

I am using MySQL 5.0 for a site that is hosted by GoDaddy (linux).
I was doing some testing on my web app, and suddenly I noticed that the pages were refreshing really slowly. Finally, after a long wait, I got to a page that said something along the lines of "MySQL Error, Too many connections...", and it pointed to my config.php file which connects to the database.
It has just been me connecting to the database, no other users. On each of my pages, I include the config.php file at the top, and close the mysql connection at the end of the page. There may be several queries in between. I fear that I am not closing mysql connections enough (mysql_close()).
However, when I try to close them after running a query, I receive connection errors on the page. My pages are PHP and HTML. When I try to close a query, it seems that the next one won't connect. Would I have to include config.php again after the close in order to connect?
This error scared me because in 2 weeks, about 84 people start using this web application.
Thanks.
EDIT:
Here is some pseudo-code of my page:
require_once('../scripts/config.php');
<?php
mysql_query..
if(this button is pressed){
mysql_query...
}
if(this button is pressed){
mysql_query...
}
if(this button is pressed){
mysql_query...
}
?>
some html..
..
..
..
..
<?php
another mysql_query...
?>
some more html..
..
..
<?php mysql_close(); ?>
I figured that this way, each time the page opens, the connection opens, and then the connection closes when the page is done loading. Then, the connection opens again when someone clicks a button on the page, and so on...
EDIT:
Okay, so I just got off the phone with GoDaddy. Apparently, with my Economy Package, I'm limited to 50 connections at a time. While my issue today happened with only me accessing the site, they said that they were having some server problems earlier. However, seeing as how I am going to have 84 users for my web app, I should probably upgrade to "Deluxe", which allows for 100 connections at a time. On a given day, there may be around 30 users accessing my site at a time, so I think the 100 would be a safer bet. Do you guys agree?
Shared-hosting providers generally allow a pretty small amount of simultaneous connections for the same user.
What your code does is :
open a connection to the MySQL server
do it's stuff (generating the page)
close the connection at the end of the page.
The last step, when done at the end of the page is not mandatory : (quoting mysql_close's manual) :
Using mysql_close() isn't usually
necessary, as non-persistent open
links are automatically closed at the
end of the script's execution.
But note you probably shouldn't use persistent connections anyway...
Two tips :
use mysql_connect insead of mysql_pconnect (already OK for you)
Set the fourth parameter of mysql_connect to false (already OK for you, as it's the default value) : (quoting the manual) :
If a second call is made to
mysql_connect() with the same
arguments, no new link will be
established, but instead, the link
identifier of the already opened link
will be returned.
The new_link
parameter modifies this behavior and
makes mysql_connect() always open a
new link, even if mysql_connect() was
called before with the same
parameters.
What could cause the problem, then ?
Maybe you are trying to access several pages in parallel (using multiple tabs in your browser, for instance), which will simulate several users using the website at the same time ?
If you have many users using the site at the same time and the code between mysql_connect and the closing of the connection takes lots of time, it will mean many connections being opened at the same time... And you'll reach the limit :-(
Still, as you are the only user of the application, considering you have up to 200 simultaneous connections allowed, there is something odd going on...
Well, thinking about "too many connections" and "max_connections"...
If I remember correctly, max_connections does not limit the number of connections you can open to the MySQL Server, but the total number of connections that can bo opened to that server, by anyone connecting to it.
Quoting MySQL's documentation on Too many connections :
If you get a Too many connections
error when you try to connect to the
mysqld server, this means that all
available connections are in use by
other clients.
The number of connections allowed is
controlled by the max_connections
system variable. Its default value is
100. If you need to support more connections, you should set a larger
value for this variable.
So, actually, the problem might not come from you nor your code (which looks fine, actually) : it might "just" be that you are not the only one trying to connect to that MySQL server (remember, "shared hosting"), and that there are too many people using it at the same time...
... And if I'm right and it's that, there's nothing you can do to solve the problem : as long as there are too many databases / users on that server and that max_connection is set to 200, you will continue suffering...
As a sidenote : before going back to GoDaddy asking them about that, it would be nice if someone could validate what I just said ^^
I had about 18 months of dealing with this (http://ianchanning.wordpress.com/2010/08/25/18-months-of-dealing-with-a-mysql-too-many-connections-error/)
The solutions I had (that would apply to you) in the end were:
tune the database according to MySQLTuner.
defragment the tables weekly based on this post
Defragmenting bash script from the post:
#!/bin/bash
# Get a list of all fragmented tables
FRAGMENTED_TABLES="$( mysql -e `use information_schema; SELECT TABLE_SCHEMA,TABLE_NAME
FROM TABLES WHERE TABLE_SCHEMA NOT IN ('information_schema','mysql') AND
Data_free > 0` | grep -v '^+' | sed 's,t,.,' )"
for fragment in $FRAGMENTED_TABLES; do
database="$( echo $fragment | cut -d. -f1 )"
table="$( echo $fragment | cut -d. -f2 )"
[ $fragment != "TABLE_SCHEMA.TABLE_NAME" ] && mysql -e "USE $database;
OPTIMIZE TABLE $table;" > /dev/null 2>&1
done
Make sure you are not using persistent connections. This is usually a bad idea..
If you've got that .. At the very most you will need to support just as much connections as you have apache processes. Are you able to change the max_connections setting?
Are you completely sure that the database server is completely dedicated to you?
Log on to the datbase as root and use "SHOW PROCESSLIST" to see who's connected. Ideally hook this into your monitoring system to view how many connections there are over time and alert if there are too many.
The maximum database connections can be configured in my.cnf, but watch out for running out of memory or address space.
If you have shell access, use netstat to see how many sockets are opened to your database and where they come from.
On Linux, type:
netstat -n -a |grep 3306
On windows, type:
netstat -n -a |findstr 3306
The solution could one of these, i came across this in a MCQA test, even i did not understood which one is right!
Set this in my.cnf "set-variable=max_connections=200"
Execute the command "SET GLOBALmax_connections = 200"
Use always mysql_connect() function in order to connect to the mysql server
Use always mysql_pconnect() function in order to connect to the mysql server
Followings are possible solutions:
1) Increase the max connection setting by setting the global variable in mysql.
set global max_connection=200;
Note: It will increase the server load.
2) Empty your connection pool as below :
FLUSH HOSTS;
3) check your processList and kill specific processlist if you don't want any of them.
You may refer this :-
article link

Categories