find_in_set and find_in_set unexpected result - mysql

USE mysql;
DROP PROCEDURE IF EXISTS ShowUsers;
DELIMITER $
CREATE PROCEDURE `ShowUsers`(IN KnownUsers varchar(500), IN KnownHosts varchar(500))
BEGIN
SELECT
user,host
FROM
user
WHERE
NOT FIND_IN_SET(host, KnownHosts)
AND
NOT FIND_IN_SET(user, KnownUsers)
ORDER BY user, host ASC;
END $
DELIMITER ;
Example complete data to work with:
+-------------+-------------+
| user | host |
+-------------+-------------+
| knownuser1 | 192.168.1.5 |
| knownuser2 | 192.168.1.5 |
| unknownuser | 192.168.1.5 | # I want this result to show
| someuser1 | 192.168.1.6 |
| someuser2 | 192.168.1.6 |
| someuser3 | 192.168.1.6 |
| root | localhost |
+-------------+-------------+
I have marked the result I would want to show from running the procedure, basically the two IN parameters are known users, and known hosts those that should be have a user record on this database.
Calling the function like this
# users and hostnames(ips) to match for exclusion from results.
SET #Usernames = 'knownuser1,knownuser2';
SET #Hostnames = '192.168.1.5';
CALL ShowUsers(#Usernames, #Hostnames);
Expected Result:
+-------------+-------------+
| user | host |
+-------------+-------------+
| unknownuser | 192.168.1.5 | # I want this result to show
| someuser1 | 192.168.1.6 |
| someuser2 | 192.168.1.6 |
| someuser3 | 192.168.1.6 |
| root | localhost |
+-------------+-------------+
Actual Result:
+-------------+-------------+
| user | host |
+-------------+-------------+
| someuser1 | 192.168.1.6 |
| someuser2 | 192.168.1.6 |
| someuser3 | 192.168.1.6 |
| root | localhost |
+-------------+-------------+
Explanation (off this topic but I think I should clarify) The reason I want this procedure to work, I have a master server with multiple remote slaves, the slaves need to have access to the masters database which means they also have to have "root" access, they can create/reconfigure their own access credentials. The problem with this is if one of those servers were ever compromised it would leave open the chance to have a new user added with credentials to basically all of the database. Wide open and free to take.
I could lock the slaves out after initial configuration and manually open up the door, run an update and then lock it again which would be pretty laborious for the application and make the application virtually useless.
The idea I'm going with right now is to run this procedure via cron run script and check for unknown users/hosts and lock that slave server out of the database until I accept or reject the user from the main application.

The condition in the WHERE clause is:
NOT FIND_IN_SET(host, KnownHosts) AND NOT FIND_IN_SET(user, KnownUsers)
which is equivalent to:
NOT (FIND_IN_SET(host, KnownHosts) OR FIND_IN_SET(user, KnownUsers))
which means that you want to exclude the rows for which:
host is included in KnownHosts or user is included in KnownUsers.
So for your sample data, the row:
unknownuser | 192.168.1.5
will not be returned, because host = '192.168.1.5' and it is included in KnownHosts (= '192.168.1.5').
Maybe change the logical operator to OR, if this is the logic that you want to apply:
NOT FIND_IN_SET(host, KnownHosts) OR NOT FIND_IN_SET(user, KnownUsers)

Related

Supply user host pairs to be excluded from mysql results

Data to work with:
+-------------+-------------+
| user | host |
+-------------+-------------+
| user1 | host1 | -
| user1 | ip1 | -
| user1 | host2 | *
| user2 | host2 | -
| user2 | ip2 | -
| unknown | unknown | +
| user1 | unknown | +
| unknown | host | +
+-------------+-------------+
The symbol to the right of the table are:
- do not show | + show as they are unknown | * because a user can only connect to one host, unless I had authorised it in which case I would supply the user host pair to the call also and it would not show.
Thats how I want things to work anyway.
This is where I am at with help from my question and as there is now a further condition a new question needs asking.
Current procedure
USE mysql;
DROP PROCEDURE IF EXISTS ShowUsers;
DELIMITER $
CREATE PROCEDURE `ShowUsers`(
IN KnownUsers varchar(500),
IN KnownHosts varchar(500)
)
BEGIN
SELECT
user,host
FROM
user
WHERE
NOT FIND_IN_SET(host, KnownHosts)
AND
NOT FIND_IN_SET(user, KnownUsers)
ORDER BY user, host ASC;
END $
DELIMITER ;
Calling the procedure like this
# known users and known hostnames or ips to match and exclude from results.
SET #Usernames = 'user1,user2';
SET #Hostnames = 'host1,host2,ip1,ip2'
CALL ShowUsers(#Usernames, #Hostnames);
Intended Result:
+-------------+-------------+
| user | host |
+-------------+-------------+
| user1 | host2 | *
| unknown | unknown | +
| user1 | unknown | +
| unknown | host | +
+-------------+-------------+
I want to be able to supply multiple user:host pairs of (known legitimate credentials) and return results that do not match, so return only suspect/illegitimate credentials in the query results.
I have created a fiddle https://www.db-fiddle.com/f/xb7dWXbkokHGbcPdzR7BUa/4 Hopefully you can see where I am going with this.
Based on whatever I could understand from your problem statement, you will need to use multiple string operations to satisfy your conditions (explanation in inline comments below):
Query
SELECT
`user`,`host`
FROM
tbl
WHERE
-- NOT condition to avoid returning one-to-one mapping between `user` and `host`
-- If `user` exist in the #Usernames, and the position of the
-- `user` matches with the position of the `host` in the #Hostnames
NOT (
FIND_IN_SET(`user`, #Usernames) > 0
-- Host and User are at same position in the lists
AND FIND_IN_SET(`user`, #Usernames) = FIND_IN_SET(`host`, #Hostnames)
)
AND
-- NOT condition to handle `host` at the end of #Hostnames list, where
-- there is no corresponding `user` mapped
NOT (
FIND_IN_SET(`host`, #Hostnames) > CHAR_LENGTH(#Usernames)
- CHAR_LENGTH(REPLACE(#Usernames, ',', ''))
+ 1
);
Result
| user | host |
| ------- | ------- |
| user1 | host2 |
| unknown | unknown |
| user1 | unknown |
| unknown | host |
View on DB Fiddle
Caveat: Above query will not work when there is no user in the #Usernames list. For brevity purpose, I avoided making the conditions more complex to handle that. Moreover, I doubt that in your practical use-case, you would have a situation where there are no user in the list.
This construct works (but not efficiently for huge tables):
WHERE (user, host) NOT IN ( ('u1', 'h1'), ('u2', 'h2), ... )
For further discussion, see "row constructor".

Intercept the id or the command of a Rollback process in MySQL

Is it possible to find the process ID or the command that is executed for a rollback ?
More specifically :
The Information_Schema of MySQL has a specific table named processlist. This contains the details about every ongoing process in MySQL. An example of the table looks like this:
mysql> select * from processlist;
+----+------+-----------+--------------------+---------+------+------------+---------------------------+
| ID | USER | HOST | DB | COMMAND | TIME | STATE | INFO |
+----+------+-----------+--------------------+---------+------+------------+---------------------------+
| 5 | root | localhost | information_schema | Query | 5 | User sleep | select sleep(20) |
| 4 | root | localhost | information_schema | Query | 0 | executing | select * from processlist |
+----+------+-----------+--------------------+---------+------+------------+---------------------------+
Is it possible for me to intercept a Rollback and grab its ID or INFO from this table ? The issue I have been facing is that any Rollback I execute gets completed before I am able to intercept its ID from the Table.

Trying to send mail alert for mysql

how to send mail alert for MySQL?
can we send alerts when the MySQL has large number of connections, or MySQL is not responding properly. Can someone help me to solve this prolem ?
You can do this in a number of ways. SHOW FULL PROCESSLIST; query would give you information about the number of connections as well as the queries being executed by each connection(thread). A sample result is as follows.
mysql> SHOW FULL PROCESSLIST;
+------+------+--------------------+------+---------+------+-------+-----------------------+
| Id | User | Host | db | Command | Time | State | Info |
+------+------+--------------------+------+---------+------+-------+-----------------------+
| 1298 | root | 192.168.1.76:37648 | NULL | Sleep | 0 | | NULL |
| 1491 | root | localhost | NULL | Query | 0 | init | show full processlist |
+------+------+--------------------+------+---------+------+-------+-----------------------+
If you are only concerned with the number of current connection(threads) you can use the following query.
mysql> SHOW STATUS WHERE `variable_name` = 'Threads_connected';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| Threads_connected | 2 |
+-------------------+-------+
Now about the mail alerts, you can setup a cron job(shell script) to fire a mail alert as soon as the number of current connections exceed a certain limit. mail command can be used for this.
$ echo "Max MySQL Connections reached"| mail -s "your subject" your#email.com
Also, I came across a great MySQL Monitoring tool- MONyog. It would let you setup mail alerts for any of the MySQL variable.

Unauthenticated user in mysql processes list - hack attempt?

I see frequently when I run mysqladmin proc or when I review the MySQL Server process list a user marked with: unauthenticated user trying to connect.
+-----+----------------------+--------------+-----------------+---------+------+------------------+------------------+-----------+---------------+-----------+
| Id | User | Host | db | Command | Time | State | Info | Rows_sent | Rows_examined | Rows_read |
+-----+----------------------+--------------+-----------------+---------+------+------------------+------------------+-----------+---------------+-----------+
| 40 | unauthenticated user | x.x.x.x:xxxx | | Connect | | Reading from net | | 0 | 0 | 0 |
What may causes such thing?
Is that normal, or should I investigate my system for any vulnerability or security breach?
Thanks
unauthenticated user is the user connected and not yet sent authentication credentials. Doesn't look like a hack attempt to me.

How to delete sleep process in Mysql

I found that my mysql sever have many of connection who is sleep. i want to delete them all.
so how i can configure my mysql server than then delete or dispose the connection who is in sleep not currently in process.
are this possible to delete this thing in mysql tell me how i can do following
a connection allow only one time datareader open and destroy the connection [process] after giving resposnse of query.
If you want to do it manually you can do like this:
login to Mysql as admin:
mysql -uroot -ppassword;
And than run command:
mysql> show processlist;
You will get something like below :
+----+-------------+--------------------+----------+---------+------+-------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-------------+--------------------+----------+---------+------+-------+------------------+
| 49 | application | 192.168.44.1:51718 | XXXXXXXX | Sleep | 183 | | NULL ||
| 55 | application | 192.168.44.1:51769 | XXXXXXXX | Sleep | 148 | | NULL |
| 56 | application | 192.168.44.1:51770 | XXXXXXXX | Sleep | 148 | | NULL |
| 57 | application | 192.168.44.1:51771 | XXXXXXXX | Sleep | 148 | | NULL |
| 58 | application | 192.168.44.1:51968 | XXXXXXXX | Sleep | 11 | | NULL |
| 59 | root | localhost | NULL | Query | 0 | NULL | show processlist |
+----+-------------+--------------------+----------+---------+------+-------+------------------+
You will see complete details of different connections. Now you can kill the sleeping connection as below:
mysql> kill 52;
Query OK, 0 rows affected (0.00 sec)
Why would you want to delete a sleeping thread? MySQL creates threads for connection requests, and when the client disconnects the thread is put back into the cache and waits for another connection.
This reduces a lot of overhead of creating threads 'on-demand', and it's nothing to worry about. A sleeping thread uses about 256k of memory.
you can find all working process execute the sql:
show process;
and you will find the sleep process, if you want terminate it, please remember the processid and excute this sql:
kill processid
but actually you can set a timeout variable in my.cnf:
wait_timeout=15
connect_timeout=10
interactive_timeout=100
for me with MySql server on windows,
I update the file (because cannot set variable with sql request due privileges):
D:\MySQL\mysql-5.6.48-winx64\my.ini
add the lines:
wait_timeout=61
interactive_timeout=61
restart service, and acknowledge new values with:
SHOW VARIABLES LIKE '%_timeout';
==> i do a connection tests and after 1 minutes all 10+ connections in sleep are disapeared!