Repository: sysown/proxysql (language: cpp)

Issue:
[ERROR] RECEIVED AN UNKNOWN COMMAND: 31 -- PLEASE REPORT A BUG
Hello,

Using MySqlConnector client for .NET (https://github.com/mysql-net/MySqlConnector) I get the following error in ProxySQL, version 2.0.:

`[ERROR] RECEIVED AN UNKNOWN COMMAND: 31 -- PLEASE REPORT A BUG`

Looking at the source code I see that `[1f] COM_RESET_CONNECTION (31)` is not implemented in [MySQL_Session.cpp](https://github.com/sysown/proxysql/blob/3fdf4cf396c2b9f80025e8182a58c70f8901df94/lib/MySQL_Session.cpp), I see `_MYSQL_COM_RESET_CONNECTION` in [proxysql_structs.h](https://github.com/sysown/proxysql/blob/a21da6b450a5bbb3f4a66a221a73627d1224114d/include/proxysql_structs.h), but it is not used.

Any chance that it can be implemented? Maybe temporarily using change user functionality?

Thanks in advance!
[ERROR] RECEIVED AN UNKNOWN COMMAND: 31 -- PLEASE REPORT A BUG
Hello,

Using MySqlConnector client for .NET (https://github.com/mysql-net/MySqlConnector) I get the following error in ProxySQL, version 2.0.:

`[ERROR] RECEIVED AN UNKNOWN COMMAND: 31 -- PLEASE REPORT A BUG`

Looking at the source code I see that `[1f] COM_RESET_CONNECTION (31)` is not implemented in [MySQL_Session.cpp](https://github.com/sysown/proxysql/blob/3fdf4cf396c2b9f80025e8182a58c70f8901df94/lib/MySQL_Session.cpp), I see `_MYSQL_COM_RESET_CONNECTION` in [proxysql_structs.h](https://github.com/sysown/proxysql/blob/a21da6b450a5bbb3f4a66a221a73627d1224114d/include/proxysql_structs.h), but it is not used.

Any chance that it can be implemented? Maybe temporarily using change user functionality?

Thanks in advance!


Discussion / hints:
Hi @nicolasgarfinkiel .
Indeed, `COM_RESET_CONNECTION` is not implemented yet.

Thank you for the report.
This error occurs on the following version: proxysql-1.4.12-1.2.el7.x86_64 as well.
Right now this is not a major issue for us, just the proxysql.log being spammed
Is there any way to stop this from happening by any chance? maybe a MySqlConnector option?
did u find a workaround @nicolasgarfinkiel ??

Hi @rohitkeshwani07, sorry for the late reply. The workaround was to specify in the client to use 5.7 version of MySQL protocol to force use of COM_CHANGE_USER instead of COM_RESET_CONNECTION (that's command 31). They are basically the same, one being more lightweight than the other. Besides, in my use case there was no need to connect with a higher protocol version, even if using MySQL and sending queries that rely on MySQL 8+.  
I am guessing you did that by specifying `server_version="5.7.23-logSourcedistribution"` in proxysql conf. It didn't work for me. 
Nope, that's something you specify at client level, ie: MySqlConnector
ok... Don't u think, if proxysql is informing version as 5.7 to the client... as it picks from `server_version`... client should use 5.7 protocol.
I just noticed (due to server disk space filling up) that I am seeing this in my logs hundreds of times per second.

What is the path forward here? Is there a way to silence these logs or fix clients? I am unable to downgrade to 5.7 protocol on some of my connecting clients so the above "workaround" is not an easy solution for me.
@peppy With MySqlConnector setting client version to 5.7 only affects the way the connection is cleaned up when it returns to the pool, instead of using COM_RESET_CONNECTION (31), it uses COM_CHANGE_USER. The former is a lighter version of the latter, but it does not affect performance whatsoever.

However, I dunno if changing the client version on other platforms affects client another behaviour.
Unfortunately it does affect behaviour for us (laravel sends commands with proxysql cannot handle if set to 5.x). Is there any other solution?
@peppy 
laravel sends commands with proxysql cannot handle if set to 5.x

i think that is just
https://github.com/laravel/framework/blob/0b12ef19623c40e22eff91a4b48cb13b3b415b25/src/Illuminate/Database/Connectors/MySqlConnector.php#L180

u can overwrite this function 
Also this is happening for me only when we run an alter query directly on mysql without going from proxysql... so we decided to stop proxysql when running alters.

you may want to test this as well.
Is there any way to get an actual fix for this pushed? We've fixed laralvel, but I have JDBC connectors which are also complaining about the version mismatch (trying to access `query_cache_size` which doesn't exist, for instance) and this really feels like a weird oversight which should be simple to fix (at very least just have the ability to silence the error).
@renecannao 
Is it planned to support COM_RESET_CONNECTION in proxysql v2?
FYI - I ran into this same problem with our .NET connector code in an older .NET Core 2.1 application (using MySqlConnector 0.57.0).

I found that setting mysql-server_version to 5.5.0 resolved the problem, although I admit to not knowing exactly why that worked.

We originally set mysql-server_version to 5.7.32-log to match our Azure MySQL server, but then we had this problem spamming our logs constantly.

```
UPDATE global_variables SET variable_value='5.5.0' WHERE variable_name='mysql-server_version';
LOAD MYSQL VARIABLES TO RUNTIME;
SAVE MYSQL VARIABLES TO DISK;
PROXYSQL RESTART;
```
Hi @nicolasgarfinkiel .
Indeed, `COM_RESET_CONNECTION` is not implemented yet.

Thank you for the report.
This error occurs on the following version: proxysql-1.4.12-1.2.el7.x86_64 as well.
Right now this is not a major issue for us, just the proxysql.log being spammed
Is there any way to stop this from happening by any chance? maybe a MySqlConnector option?
did u find a workaround @nicolasgarfinkiel ??

Hi @rohitkeshwani07, sorry for the late reply. The workaround was to specify in the client to use 5.7 version of MySQL protocol to force use of COM_CHANGE_USER instead of COM_RESET_CONNECTION (that's command 31). They are basically the same, one being more lightweight than the other. Besides, in my use case there was no need to connect with a higher protocol version, even if using MySQL and sending queries that rely on MySQL 8+.  
I am guessing you did that by specifying `server_version="5.7.23-logSourcedistribution"` in proxysql conf. It didn't work for me. 
Nope, that's something you specify at client level, ie: MySqlConnector
ok... Don't u think, if proxysql is informing version as 5.7 to the client... as it picks from `server_version`... client should use 5.7 protocol.
I just noticed (due to server disk space filling up) that I am seeing this in my logs hundreds of times per second.

What is the path forward here? Is there a way to silence these logs or fix clients? I am unable to downgrade to 5.7 protocol on some of my connecting clients so the above "workaround" is not an easy solution for me.
@peppy With MySqlConnector setting client version to 5.7 only affects the way the connection is cleaned up when it returns to the pool, instead of using COM_RESET_CONNECTION (31), it uses COM_CHANGE_USER. The former is a lighter version of the latter, but it does not affect performance whatsoever.

However, I dunno if changing the client version on other platforms affects client another behaviour.
Unfortunately it does affect behaviour for us (laravel sends commands with proxysql cannot handle if set to 5.x). Is there any other solution?
@peppy 
laravel sends commands with proxysql cannot handle if set to 5.x

i think that is just
https://github.com/laravel/framework/blob/0b12ef19623c40e22eff91a4b48cb13b3b415b25/src/Illuminate/Database/Connectors/MySqlConnector.php#L180

u can overwrite this function 
Also this is happening for me only when we run an alter query directly on mysql without going from proxysql... so we decided to stop proxysql when running alters.

you may want to test this as well.
Is there any way to get an actual fix for this pushed? We've fixed laralvel, but I have JDBC connectors which are also complaining about the version mismatch (trying to access `query_cache_size` which doesn't exist, for instance) and this really feels like a weird oversight which should be simple to fix (at very least just have the ability to silence the error).
@renecannao 
Is it planned to support COM_RESET_CONNECTION in proxysql v2?
FYI - I ran into this same problem with our .NET connector code in an older .NET Core 2.1 application (using MySqlConnector 0.57.0).

I found that setting mysql-server_version to 5.5.0 resolved the problem, although I admit to not knowing exactly why that worked.

We originally set mysql-server_version to 5.7.32-log to match our Azure MySQL server, but then we had this problem spamming our logs constantly.

```
UPDATE global_variables SET variable_value='5.5.0' WHERE variable_name='mysql-server_version';
LOAD MYSQL VARIABLES TO RUNTIME;
SAVE MYSQL VARIABLES TO DISK;
PROXYSQL RESTART;
```

Fix patch:
diff --git a/.gitignore b/.gitignore
index 2882af55e1..b2302274c9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -159,7 +159,6 @@ deps/libssl/openssl-1.1.1b/
 deps/libssl/openssl-1.1.1d/
 deps/libssl/openssl-1.1.1g/
 deps/libssl/openssl-1.1.1j/
-deps/libssl/openssl-openssl-3.0.0/
 
 #google coredumper
 deps/google-coredumper/google-coredumper/
diff --git a/README.md b/README.md
index 60352d75a6..ab763f062a 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,6 @@ Useful links
 ===============	
 
 - [Official website](https://www.proxysql.com/)	
-- [Subscriptions and Support](https://proxysql.com/services/support/) 
 - [Documentation](https://www.proxysql.com/Documentation)
 - [DockerHub Repository](https://hub.docker.com/r/proxysql/proxysql)
 - [Benchmarks and blog posts](http://www.proxysql.blogspot.com/)	
diff --git a/deps/Makefile b/deps/Makefile
index ef6856dcdc..0528415d23 100644
--- a/deps/Makefile
+++ b/deps/Makefile
@@ -55,9 +55,8 @@ libssl/openssl/libssl.a:
 	cd libssl && rm -rf openssl-1.1.0h || true
 	cd libssl && rm -rf openssl-1.1.1g || true
 	cd libssl && rm -rf openssl-1.1.1j || true
-	cd libssl && rm -rf openssl-openssl-3.0.0 || true
-	cd libssl && tar -zxf openssl-3.0.0.tar.gz
-	cd libssl/openssl  && ./config no-ssl3 no-tests
+	cd libssl && tar -zxf openssl-1.1.1j.tar.gz
+	cd libssl/openssl  && ./config no-ssl3
 	cd libssl/openssl && CC=${CC} CXX=${CXX} ${MAKE}
 	cd libssl/openssl && ln -s . lib # curl wants this path
 libssl: libssl/openssl/libssl.a
@@ -289,7 +288,6 @@ cleanall:
 	cd libssl && rm -rf openssl-1.1.1d || true
 	cd libssl && rm -rf openssl-1.1.1g || true
 	cd libssl && rm -rf openssl-1.1.1j || true
-	cd libssl && rm -rf openssl-openssl-3.0.0 || true
 	cd libconfig && rm -rf libconfig-1.7.2 || true
 	cd prometheus-cpp && rm -rf prometheus-cpp-0.9.0 || true
 .PHONY: cleanall
diff --git a/deps/libssl/openssl b/deps/libssl/openssl
index 06e4a19616..b4df187df9 120000
--- a/deps/libssl/openssl
+++ b/deps/libssl/openssl
@@ -1,1 +1,1 @@
-openssl-openssl-3.0.0
\ No newline at end of file
+openssl-1.1.1j
\ No newline at end of file
diff --git a/deps/libssl/openssl-3.0.0.tar.gz b/deps/libssl/openssl-3.0.0.tar.gz
deleted file mode 100644
index c25713bd73..0000000000
Binary files a/deps/libssl/openssl-3.0.0.tar.gz and /dev/null differ
diff --git a/docker/images/proxysql/rhel-compliant/rhel6/entrypoint/entrypoint.bash b/docker/images/proxysql/rhel-compliant/rhel6/entrypoint/entrypoint.bash
index b541f2e6e7..9c4af5e350 100755
--- a/docker/images/proxysql/rhel-compliant/rhel6/entrypoint/entrypoint.bash
+++ b/docker/images/proxysql/rhel-compliant/rhel6/entrypoint/entrypoint.bash
@@ -4,6 +4,14 @@ set -eu
 echo "==> Build environment:"
 env
 
+echo "==> Dirty patching to ensure OS deps are installed"
+
+yum -y install gnutls-devel libtool || true
+yum -y install epel-release
+sed -i "s/mirrorlist=https/mirrorlist=http/" /etc/yum.repos.d/epel.repo
+yum -y install http://repo.okay.com.mx/centos/6/x86_64/release/okay-release-1-1.noarch.rpm
+yum -y upgrade automake autoconf
+
 echo "==> Cleaning"
 # Delete package if exists
 rm -f /opt/proxysql/binaries/proxysql-${CURVER}-1-${PKG_RELEASE}.x86_64.rpm || true
diff --git a/include/MySQL_HostGroups_Manager.h b/include/MySQL_HostGroups_Manager.h
index 4029085f2d..cc88dfcc87 100644
--- a/include/MySQL_HostGroups_Manager.h
+++ b/include/MySQL_HostGroups_Manager.h
@@ -95,6 +95,7 @@ class GTID_Server_Data {
 
 class MySrvConnList {
 	private:
+	PtrArray *conns;
 	MySrvC *mysrvc;
 	int find_idx(MySQL_Connection *c) {
 		//for (unsigned int i=0; i<conns_length(); i++) {
@@ -108,7 +109,6 @@ class MySrvConnList {
 		return -1;
 	}
 	public:
-	PtrArray *conns;
 	MySrvConnList(MySrvC *);
 	~MySrvConnList();
 	void add(MySQL_Connection *);
@@ -160,7 +160,7 @@ class MySrvC {	// MySQL Server Container
 	MySrvConnList *ConnectionsFree;
 	MySrvC(char *, uint16_t, uint16_t, unsigned int, enum MySerStatus, unsigned int, unsigned int _max_connections, unsigned int _max_replication_lag, unsigned int _use_ssl, unsigned int _max_latency_ms, char *_comment);
 	~MySrvC();
-	void connect_error(int, bool get_mutex=true);
+	void connect_error(int);
 	void shun_and_killall();
 	/**
 	 * Update the maximum number of used connections
@@ -609,8 +609,6 @@ class MySQL_HostGroups_Manager {
 	SQLite3_result *get_mysql_errors(bool);
 
 	void shutdown();
-	void unshun_server_all_hostgroups(const char * address, uint16_t port, time_t t, int max_wait_sec, unsigned int *skip_hid);
-	MySrvC* find_server_in_hg(unsigned int _hid, const std::string& addr, int port);
 };
 
 #endif /* __CLASS_MYSQL_HOSTGROUPS_MANAGER_H */
diff --git a/include/MySQL_Session.h b/include/MySQL_Session.h
index 7aa5441e06..68fa7dffd2 100644
--- a/include/MySQL_Session.h
+++ b/include/MySQL_Session.h
@@ -20,6 +20,8 @@ enum proxysql_session_type {
 	PROXYSQL_SESSION_NONE
 };
 
+std::string proxysql_session_type_str(enum proxysql_session_type session_type);
+
 // these structs will be used for various regex hardcoded
 // their initial use will be for sql_log_bin , sql_mode and time_zone
 // issues #509 , #815 and #816
@@ -94,7 +96,21 @@ class MySQL_Session
 	void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_PING(PtrSize_t *);
 
 	void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_CHANGE_USER(PtrSize_t *, bool *);
-
+	/**
+	 * @brief Handles the command 'COM_RESET_CONNECTION'.
+	 * @param pkt Pointer to packet received holding the 'COM_RESET_CONNECTION'.
+	 * @details 'COM_RESET_CONNECTION' command is currently supported only for 'sesssion_types':
+	 *   - 'PROXYSQL_SESSION_MYSQL'.
+	 *   - 'PROXYSQL_SESSION_SQLITE'.
+	 *  If the command is received for other sessions, the an error packet with error '1047' is sent to the
+	 *  client. If the session is supported, it performs the following operations over the current session:
+	 *   1. Store the current relevent session variables to be recovered after the 'RESET'.
+	 *   2. Perform a reset and initialization of current session.
+	 *   3. Recover the relevant session variables and other initial state associated with the current session
+	 *      user.
+	 *   4. Respond to client with 'OK' packet.
+	 */
+	void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_RESET_CONNECTION(PtrSize_t *pkt);
 	void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_SET_OPTION(PtrSize_t *);
 	void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_STATISTICS(PtrSize_t *);
 	void handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_PROCESS_KILL(PtrSize_t *);
@@ -106,11 +122,6 @@ class MySQL_Session
 	bool handler_special_queries(PtrSize_t *);
 	bool handler_CommitRollback(PtrSize_t *);
 	bool handler_SetAutocommit(PtrSize_t *);
-	/**
-	 * @brief Performs the cleanup of current session state, and the required operations to the supplied
-	 *   'MySQL_Data_Stream' required for processing further queries.
-	 * @param The 'MySQL_Data_Stream' which executed the previous query and which status should be updated.
-	 */
 	void RequestEnd(MySQL_Data_Stream *);
 	void LogQuery(MySQL_Data_Stream *);
 
@@ -214,6 +225,12 @@ class MySQL_Session
 	int user_max_connections;
 	int current_hostgroup;
 	int default_hostgroup;
+	/**
+	 * @brief Charset directly specified by the client. Supplied and updated via 'HandshakeResponse'
+	 *   and 'COM_CHANGE_USER' packets.
+	 * @details Used when session needs to be restored via 'COM_RESET_CONNECTION'.
+	 */
+	int default_charset;
 	int locked_on_hostgroup;
 	int next_query_flagIN;
 	int mirror_hostgroup;
@@ -286,18 +303,6 @@ class MySQL_Session
 	void Memory_Stats();
 	void create_new_session_and_reset_connection(MySQL_Data_Stream *_myds);
 	bool handle_command_query_kill(PtrSize_t *);
-	/**
-	 * @brief Performs the final operations after current query has finished to be executed. It updates the session
-	 *  'transaction_persistent_hostgroup', and updates the 'MySQL_Data_Stream' and 'MySQL_Connection' before
-	 *  returning the connection back to the connection pool. After this operation the session should be ready
-	 *  for handling new client connections.
-	 *
-	 * @param myds The 'MySQL_Data_Stream' which status should be updated.
-	 * @param myconn The 'MySQL_Connection' which status should be updated, and which should be returned to
-	 *   the connection pool.
-	 * @param prepared_stmt_with_no_params specifies if the processed query was a prepared statement with no
-	 *   params.
-	 */
 	void finishQuery(MySQL_Data_Stream *myds, MySQL_Connection *myconn, bool);
 	void generate_proxysql_internal_session_json(json &);
 	bool known_query_for_locked_on_hostgroup(uint64_t);
diff --git a/include/MySQL_Thread.h b/include/MySQL_Thread.h
index 7a5bde801b..308f6b8f85 100644
--- a/include/MySQL_Thread.h
+++ b/include/MySQL_Thread.h
@@ -459,7 +459,6 @@ class MySQL_Threads_Handler
 		int ping_timeout_server;
 		int shun_on_failures;
 		int shun_recovery_time_sec;
-		int unshun_algorithm;
 		int query_retries_on_failure;
 		bool client_multi_statements;
 		bool connection_warming;
diff --git a/include/proxysql_admin.h b/include/proxysql_admin.h
index 39d677654d..af744d588b 100644
--- a/include/proxysql_admin.h
+++ b/include/proxysql_admin.h
@@ -434,10 +434,8 @@ class ProxySQL_Admin {
 	bool ProxySQL_Test___Verify_mysql_query_rules_fast_routing(int *ret1, int *ret2, int cnt, int dual);
 	void ProxySQL_Test___MySQL_HostGroups_Manager_generate_many_clusters();
 	unsigned long long ProxySQL_Test___MySQL_HostGroups_Manager_read_only_action();
-#ifdef DEBUG
 	unsigned long long ProxySQL_Test___MySQL_HostGroups_Manager_HG_lookup();
-	unsigned long long ProxySQL_Test___MySQL_HostGroups_Manager_Balancing_HG5211();
-#endif
+
 	friend void admin_session_handler(MySQL_Session *sess, void *_pa, PtrSize_t *pkt);
 };
 #endif /* __CLASS_PROXYSQL_ADMIN_H */
diff --git a/include/proxysql_structs.h b/include/proxysql_structs.h
index 760467c402..82eaf1c385 100644
--- a/include/proxysql_structs.h
+++ b/include/proxysql_structs.h
@@ -747,7 +747,6 @@ __thread int mysql_thread___ping_interval_server_msec;
 __thread int mysql_thread___ping_timeout_server;
 __thread int mysql_thread___shun_on_failures;
 __thread int mysql_thread___shun_recovery_time_sec;
-__thread int mysql_thread___unshun_algorithm;
 __thread int mysql_thread___query_retries_on_failure;
 __thread bool mysql_thread___client_multi_statements;
 __thread int mysql_thread___connect_retries_on_failure;
@@ -906,7 +905,6 @@ extern __thread int mysql_thread___ping_interval_server_msec;
 extern __thread int mysql_thread___ping_timeout_server;
 extern __thread int mysql_thread___shun_on_failures;
 extern __thread int mysql_thread___shun_recovery_time_sec;
-extern __thread int mysql_thread___unshun_algorithm;
 extern __thread int mysql_thread___query_retries_on_failure;
 extern __thread bool mysql_thread___client_multi_statements;
 extern __thread int mysql_thread___connect_retries_on_failure;
@@ -1053,6 +1051,9 @@ typedef struct {
 	char * default_value;       // default value
 	bool is_global_variable;	// is it a global variable?
 } mysql_variable_st;
+
+TODO: 'SQL_CHARACTER_SET_DATABASE' is a variable that shouldn't be set, or tracked on our side, since it's meant to be only updated by the server:
+ - https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_character_set_database
 */
 mysql_variable_st mysql_tracked_variables[] {
     { SQL_CHARACTER_SET,         SETTING_CHARSET,    false, true, false,  false, false, (char *)"charset", (char *)"charset", (char *)"utf8" , true} , // should be before SQL_CHARACTER_SET_RESULTS
diff --git a/lib/MySQL_HostGroups_Manager.cpp b/lib/MySQL_HostGroups_Manager.cpp
index 163a4dc738..21c64391cc 100644
--- a/lib/MySQL_HostGroups_Manager.cpp
+++ b/lib/MySQL_HostGroups_Manager.cpp
@@ -868,7 +868,7 @@ MySrvC::MySrvC(char *add, uint16_t p, uint16_t gp, unsigned int _weight, enum My
 	ConnectionsFree=new MySrvConnList(this);
 }
 
-void MySrvC::connect_error(int err_num, bool get_mutex) {
+void MySrvC::connect_error(int err_num) {
 	// NOTE: this function operates without any mutex
 	// although, it is not extremely important if any counter is lost
 	// as a single connection failure won't make a significant difference
@@ -901,7 +901,6 @@ void MySrvC::connect_error(int err_num, bool get_mutex) {
 		case 1120:
 		case 1203: // User %s already has more than 'max_user_connections' active connections
 		case 1226: // User '%s' has exceeded the '%s' resource (current value: %ld)
-		case 3118: // Access denied for user '%s'. Account is locked..
 			return;
 			break;
 		default:
@@ -921,8 +920,7 @@ void MySrvC::connect_error(int err_num, bool get_mutex) {
 		int max_failures = ( mysql_thread___shun_on_failures > mysql_thread___connect_retries_on_failure ? mysql_thread___connect_retries_on_failure : mysql_thread___shun_on_failures) ;
 		if (__sync_add_and_fetch(&connect_ERR_at_time_last_detected_error,1) >= (unsigned int)max_failures) {
 			bool _shu=false;
-			if (get_mutex==true)
-				MyHGM->wrlock(); // to prevent race conditions, lock here. See #627
+			MyHGM->wrlock(); // to prevent race conditions, lock here. See #627
 			if (status==MYSQL_SERVER_STATUS_ONLINE) {
 				status=MYSQL_SERVER_STATUS_SHUNNED;
 				shunned_automatic=true;
@@ -930,8 +928,7 @@ void MySrvC::connect_error(int err_num, bool get_mutex) {
 			} else {
 				_shu=false;
 			}
-			if (get_mutex==true)
-				MyHGM->wrunlock();
+			MyHGM->wrunlock();
 			if (_shu) {
 			proxy_error("Shunning server %s:%d with %u errors/sec. Shunning for %u seconds\n", address, port, connect_ERR_at_time_last_detected_error , mysql_thread___shun_recovery_time_sec);
 			}
@@ -2816,13 +2813,6 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_
 								mysrvc->shunned_and_kill_all_connections=false;
 								mysrvc->connect_ERR_at_time_last_detected_error=0;
 								mysrvc->time_last_detected_error=0;
-								// note: the following function scans all the hostgroups.
-								// This is ok for now because we only have a global mutex.
-								// If one day we implement a mutex per hostgroup (unlikely,
-								// but possible), this must be taken into consideration
-								if (mysql_thread___unshun_algorithm == 1) {
-									MyHGM->unshun_server_all_hostgroups(mysrvc->address, mysrvc->port, t, max_wait_sec, &mysrvc->myhgc->hid);
-								}
 								// if a server is taken back online, consider it immediately
 								if ( mysrvc->current_latency_us < ( mysrvc->max_latency_us ? mysrvc->max_latency_us : mysql_thread___default_max_latency_ms*1000 ) ) { // consider the host only if not too far
 									if (gtid_trxid) {
@@ -2945,9 +2935,9 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_
 			return NULL; // if we reach here, we couldn't find any target
 		}
 
-/*
 		unsigned int New_sum=0;
 		unsigned int New_TotalUsedConn=0;
+
 		// we will now scan again to ignore overloaded servers
 		for (j=0; j<num_candidates; j++) {
 			mysrvc = mysrvcCandidates[j];
@@ -2965,9 +2955,7 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_
 				num_candidates--;
 			}
 		}
-*/
 
-		unsigned int New_sum=sum;
 
 		if (New_sum==0) {
 			proxy_debug(PROXY_DEBUG_MYSQL_CONNPOOL, 7, "Returning MySrvC NULL because no backend ONLINE or with weight\n");
@@ -2981,7 +2969,7 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_
 		}
 
 		// latency awareness algorithm is enabled only when compiled with USE_MYSRVC_ARRAY
-		if (sess && sess->thread->variables.min_num_servers_lantency_awareness) {
+		if (sess->thread->variables.min_num_servers_lantency_awareness) {
 			if ((int) num_candidates >= sess->thread->variables.min_num_servers_lantency_awareness) {
 				unsigned int servers_with_latency = 0;
 				unsigned int total_latency_us = 0;
@@ -3234,47 +3222,6 @@ MySQL_Connection * MySrvConnList::get_random_MyConn(MySQL_Session *sess, bool ff
 	return NULL; // never reach here
 }
 
-void MySQL_HostGroups_Manager::unshun_server_all_hostgroups(const char * address, uint16_t port, time_t t, int max_wait_sec, unsigned int *skip_hid) {
-	// we scan all hostgroups looking for a specific server to unshun
-	// if skip_hid is not NULL , the specific hostgroup is skipped
-	int i, j;
-	for (i=0; i<(int)MyHostGroups->len; i++) {
-		MyHGC *myhgc=(MyHGC *)MyHostGroups->index(i);
-		if (skip_hid != NULL && myhgc->hid == *skip_hid) {
-			// if skip_hid is not NULL, we skip that specific hostgroup
-			continue;
-		}
-		bool found = false; // was this server already found in this hostgroup?
-		for (j=0; found==false && j<(int)myhgc->mysrvs->cnt(); j++) {
-			MySrvC *mysrvc=(MySrvC *)myhgc->mysrvs->servers->index(j);
-			if (mysrvc->status==MYSQL_SERVER_STATUS_SHUNNED) {
-				// we only care for SHUNNED nodes
-				// Note that we check for address and port only for status==MYSQL_SERVER_STATUS_SHUNNED ,
-				// that means that potentially we will pass by the matching node and still looping .
-				// This is potentially an optimization because we only check status and do not perform any strcmp()
-				if (strcmp(mysrvc->address,address)==0 && mysrvc->port==port) {
-					// we found the server in this hostgroup
-					// no need to process more servers in the same hostgroup
-					found = true;
-					if (t > mysrvc->time_last_detected_error && (t - mysrvc->time_last_detected_error) > max_wait_sec) {
-						if (
-							(mysrvc->shunned_and_kill_all_connections==false) // it is safe to bring it back online
-							||
-							(mysrvc->shunned_and_kill_all_connections==true && mysrvc->ConnectionsUsed->conns_length()==0 && mysrvc->ConnectionsFree->conns_length()==0) // if shunned_and_kill_all_connections is set, ensure all connections are already dropped
-						) {
-							mysrvc->status=MYSQL_SERVER_STATUS_ONLINE;
-							mysrvc->shunned_automatic=false;
-							mysrvc->shunned_and_kill_all_connections=false;
-							mysrvc->connect_ERR_at_time_last_detected_error=0;
-							mysrvc->time_last_detected_error=0;
-						}
-					}
-				}
-			}
-		}
-	}
-}
-
 MySQL_Connection * MySQL_HostGroups_Manager::get_MyConn_from_pool(unsigned int _hid, MySQL_Session *sess, bool ff, char * gtid_uuid, uint64_t gtid_trxid, int max_lag_ms) {
 	MySQL_Connection * conn=NULL;
 	wrlock();
@@ -3601,22 +3548,8 @@ int MySQL_HostGroups_Manager::get_multiple_idle_connections(int _hid, unsigned l
 	drop_all_idle_connections();
 	int num_conn_current=0;
 	int j,k;
-	MyHGC* myhgc = NULL;
-	for (int i=0; i<(int)MyHostGroups->len; i++) {
-		if (_hid == -1) {
-			// all hostgroups must be examined
-			// as of version 2.3.2 , this is always the case
-			myhgc=(MyHGC *)MyHostGroups->index(i);
-		} else {
-			// only one hostgroup is examined
-			// as of version 2.3.2 , this never happen
-			// but the code support this functionality
-			myhgc = MyHGC_find(_hid);
-			i = (int)MyHostGroups->len; // to exit from this "for" loop
-			if (myhgc == NULL)
-				continue; // immediately exit
-		}
-		if (_hid >= 0 && _hid!=(int)myhgc->hid) continue;
+	MyHGC* myhgc = MyHGC_find(_hid);
+	if (myhgc) {
 		for (j=0; j<(int)myhgc->mysrvs->cnt(); j++) {
 			MySrvC *mysrvc=(MySrvC *)myhgc->mysrvs->servers->index(j);
 			//PtrArray *pa=mysrvc->ConnectionsFree->conns;
@@ -7045,28 +6978,4 @@ void MySQL_HostGroups_Manager::update_aws_aurora_set_reader(int _whid, int _rhid
 	free(domain_name);
 }
 
-MySrvC* MySQL_HostGroups_Manager::find_server_in_hg(unsigned int _hid, const std::string& addr, int port) {
-	MySrvC* f_server = nullptr;
-
-	MyHGC* myhgc = nullptr;
-	for (uint32_t i = 0; i < MyHostGroups->len; i++) {
-		myhgc = static_cast<MyHGC*>(MyHostGroups->index(i));
-
-		if (myhgc->hid == _hid) {
-			break;
-		}
-	}
-
-	if (myhgc != nullptr) {
-		for (uint32_t j = 0; j < myhgc->mysrvs->cnt(); j++) {
-			MySrvC* mysrvc = static_cast<MySrvC*>(myhgc->mysrvs->servers->index(j));
-
-			if (strcmp(mysrvc->address, addr.c_str()) == 0 && mysrvc->port == port) {
-				f_server = mysrvc;
-			}
-		}
-	}
-
-	return f_server;
-}
 
diff --git a/lib/MySQL_Protocol.cpp b/lib/MySQL_Protocol.cpp
index c423a5efda..701442a748 100644
--- a/lib/MySQL_Protocol.cpp
+++ b/lib/MySQL_Protocol.cpp
@@ -1347,6 +1347,7 @@ bool MySQL_Protocol::process_pkt_COM_CHANGE_USER(unsigned char *pkt, unsigned in
 	unsigned char *user=NULL;
 	char *password=NULL;
 	char *db=NULL;
+	char* user_attributes=NULL;
 	mysql_hdr hdr;
 	memcpy(&hdr,pkt,sizeof(mysql_hdr));
 	int default_hostgroup=-1;
@@ -1373,11 +1374,12 @@ bool MySQL_Protocol::process_pkt_COM_CHANGE_USER(unsigned char *pkt, unsigned in
 		password=GloClickHouseAuth->lookup((char *)user, USERNAME_FRONTEND, &_ret_use_ssl, &default_hostgroup, NULL, NULL, &transaction_persistent, NULL, NULL, &sha1_pass);
 #endif /* PROXYSQLCLICKHOUSE */
 	} else {
-		password=GloMyAuth->lookup((char *)user, USERNAME_FRONTEND, &_ret_use_ssl, &default_hostgroup, NULL, NULL, &transaction_persistent, NULL, NULL, &sha1_pass, NULL);
+		password=GloMyAuth->lookup((char *)user, USERNAME_FRONTEND, &_ret_use_ssl, &default_hostgroup, NULL, NULL, &transaction_persistent, NULL, NULL, &sha1_pass, &user_attributes);
 	}
 	// FIXME: add support for default schema and fast forward, see issue #255 and #256
 	(*myds)->sess->default_hostgroup=default_hostgroup;
 	(*myds)->sess->transaction_persistent=transaction_persistent;
+	(*myds)->sess->user_attributes=user_attributes;
 	if (password==NULL) {
 		ret=false;
 	} else {
@@ -1463,6 +1465,8 @@ bool MySQL_Protocol::process_pkt_COM_CHANGE_USER(unsigned char *pkt, unsigned in
 			ret = false;
 			return ret;
 		}
+		// set the default charset for this session
+		(*myds)->sess->default_charset = charset;
 		if ((*myds)->sess->user_attributes) {
 			if (user_attributes_has_spiffe(__LINE__, __func__, user)) {
 				// if SPIFFE was used, CHANGE_USER is not allowed.
@@ -1475,6 +1479,18 @@ bool MySQL_Protocol::process_pkt_COM_CHANGE_USER(unsigned char *pkt, unsigned in
 				ret = false;
 				return ret;
 			}
+
+			char* user_attributes = (*myds)->sess->user_attributes;
+			if (strlen(user_attributes)) {
+				nlohmann::json j_user_attributes = nlohmann::json::parse(user_attributes);
+				auto default_transaction_isolation = j_user_attributes.find("default-transaction_isolation");
+
+				if (default_transaction_isolation != j_user_attributes.end()) {
+					std::string def_trx_isolation_val =
+						j_user_attributes["default-transaction_isolation"].get<std::string>();
+					mysql_variables.client_set_value((*myds)->sess, SQL_ISOLATION_LEVEL, def_trx_isolation_val.c_str());
+				}
+			}
 		}
 		assert(sess);
 		assert(sess->client_myds);
@@ -1781,6 +1797,8 @@ bool MySQL_Protocol::process_pkt_handshake_response(unsigned char *pkt, unsigned
 			ret = false;
 			goto __exit_do_auth;
 		}
+		// set the default session charset
+		(*myds)->sess->default_charset = charset;
 	}
 	if (session_type == PROXYSQL_SESSION_CLICKHOUSE) {
 #ifdef PROXYSQLCLICKHOUSE
diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp
index 130dbc80cc..ba3de7c86f 100644
--- a/lib/MySQL_Session.cpp
+++ b/lib/MySQL_Session.cpp
@@ -2,6 +2,7 @@
 #include "MySQL_Thread.h"
 #include "proxysql.h"
 #include "cpp.h"
+#include "proxysql_utils.h"
 #include "re2/re2.h"
 #include "re2/regexp.h"
 #include "SpookyV2.h"
@@ -86,6 +87,24 @@ extern ClickHouse_Authentication *GloClickHouseAuth;
 extern ClickHouse_Server *GloClickHouseServer;
 #endif /* PROXYSQLCLICKHOUSE */
 
+std::string proxysql_session_type_str(enum proxysql_session_type session_type) {
+	if (session_type == PROXYSQL_SESSION_MYSQL) {
+		return "PROXYSQL_SESSION_MYSQL";
+	} else if (session_type == PROXYSQL_SESSION_ADMIN) {
+		return "PROXYSQL_SESSION_ADMIN";
+	} else if (session_type == PROXYSQL_SESSION_STATS) {
+		return "PROXYSQL_SESSION_STATS";
+	} else if (session_type == PROXYSQL_SESSION_SQLITE) {
+		return "PROXYSQL_SESSION_SQLITE";
+	} else if (session_type == PROXYSQL_SESSION_CLICKHOUSE) {
+		return "PROXYSQL_SESSION_CLICKHOUSE";
+	} else if (session_type == PROXYSQL_SESSION_MYSQL_EMU) {
+		return "PROXYSQL_SESSION_MYSQL_EMU";
+	} else {
+		return "PROXYSQL_SESSION_NONE";
+	}
+};
+
 Session_Regex::Session_Regex(char *p) {
 	s=strdup(p);
 	re2::RE2::Options *opt2=new re2::RE2::Options(RE2::Quiet);
@@ -3318,6 +3337,9 @@ bool MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C
 		case _MYSQL_COM_PROCESS_KILL:
 			handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_PROCESS_KILL(pkt);
 			break;
+		case _MYSQL_COM_RESET_CONNECTION:
+			handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_RESET_CONNECTION(pkt);
+			break;
 		default:
 			return false;
 			break;
@@ -3730,21 +3752,6 @@ int MySQL_Session::get_pkts_from_client(bool& wrong_pass, PtrSize_t& pkt) {
 			case FAST_FORWARD:
 				mybe->server_myds->PSarrayOUT->add(pkt.ptr, pkt.size);
 				break;
-			// This state is required because it covers the following situation:
-			//  1. A new connection is created by a client and the 'FAST_FORWARD' mode is enabled.
-			//  2. The first packet received for this connection isn't a whole packet, i.e, it's either
-			//     split into multiple packets, or it doesn't fit 'queueIN' size (typically
-			//     QUEUE_T_DEFAULT_SIZE).
-			//  3. Session is still in 'CONNECTING_SERVER' state, BUT further packets remain to be received
-			//     from the initial split packet.
-			//
-			//  Because of this, packets received during 'CONNECTING_SERVER' when the previous state is
-			//  'FAST_FORWARD' should be pushed to 'PSarrayOUT'.
-			case CONNECTING_SERVER:
-				if (previous_status.empty() == false && previous_status.top() == FAST_FORWARD) {
-					mybe->server_myds->PSarrayOUT->add(pkt.ptr, pkt.size);
-					break;
-				}
 			case session_status___NONE:
 			default:
 				handler___status_NONE_or_default(pkt);
@@ -4559,12 +4566,8 @@ int MySQL_Session::handler() {
 					if (mysql_thread___log_mysql_warnings_enabled) {
 						auto warn_no = mysql_warning_count(myconn->mysql);
 						if (warn_no > 0) {
-							RequestEnd(myds);
-							writeout();
-
 							myconn->async_state_machine=ASYNC_IDLE;
 							myds->DSS=STATE_MARIADB_GENERIC;
-
 							NEXT_IMMEDIATE(SHOW_WARNINGS);
 						}
 					}
@@ -4668,41 +4671,26 @@ int MySQL_Session::handler() {
 			break;
 
 		case SHOW_WARNINGS:
-			// Performs a 'SHOW WARNINGS' query over the current backend connection and returns the connection back
-			// to the connection pool when finished. Actual logging of received warnings is performed in
-			// 'MySQL_Connection' while processing 'ASYNC_USE_RESULT_CONT'.
 			{
 				MySQL_Data_Stream *myds=mybe->server_myds;
 				MySQL_Connection *myconn=myds->myconn;
-
-				// Setting POLLOUT is required just in case this state has been reached when 'RunQuery' from
-				// 'PROCESSING_QUERY' state has immediately return. This is because in case 'mysql_real_query_start'
-				// immediately returns with '0' the session is never processed again by 'MySQL_Thread', and 'revents' is
-				// never updated with the result of polling through the 'MySQL_Thread::mypolls'.
-				myds->revents |= POLLOUT;
-
-				int rc = myconn->async_query(
-					mybe->server_myds->revents,(char *)"SHOW WARNINGS", strlen((char *)"SHOW WARNINGS")
-				);
-				if (rc == 0 || rc == -1) {
-					// Cleanup the connection resulset from 'SHOW WARNINGS' for the next query.
-					if (myconn->MyRS != NULL) {
-						delete myconn->MyRS;
-						myconn->MyRS = NULL;
-					}
-
-					if (rc == -1) {
-						int myerr = mysql_errno(myconn->mysql);
-						proxy_error(
-							"'SHOW WARNINGS' failed to be executed over backend connection with error: '%d'\n", myerr
-						);
-					}
+				int pre_rc = myconn->async_query(mybe->server_myds->revents,(char *)"show warnings", strlen((char *)"show warnings"));
+				if (pre_rc==0) {
+					int myerr=mysql_errno(myconn->mysql);
 
 					RequestEnd(myds);
-					finishQuery(myds,myconn,prepared_stmt_with_no_params);
+					writeout();
 
 					handler_ret = 0;
 					return handler_ret;
+					if ( myerr > 0 ) {
+						char sqlstate[10];
+						sprintf(sqlstate,"%s",mysql_sqlstate(mybe->server_myds->myconn->mysql));
+						RequestEnd(mybe->server_myds);
+						break;
+					}
+					mybe->server_myds->myconn->async_free_result();
+					NEXT_IMMEDIATE(PROCESSING_QUERY);
 				} else {
 					goto handler_again;
 				}
@@ -6311,6 +6299,53 @@ void MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C
 	}
 }
 
+void MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_RESET_CONNECTION(PtrSize_t *pkt) {
+	proxy_debug(PROXY_DEBUG_MYSQL_COM, 5, "Got MYSQL_COM_RESET_CONNECTION packet\n");
+
+	if (session_type == PROXYSQL_SESSION_MYSQL || session_type == PROXYSQL_SESSION_SQLITE) {
+		// Backup the current relevant session values
+		int default_hostgroup = this->default_hostgroup;
+		bool transaction_persistent = this->transaction_persistent;
+
+		// Re-initialize the session
+		reset();
+		init();
+
+		// Recover the relevant session values
+		this->default_hostgroup = default_hostgroup;
+		this->transaction_persistent = transaction_persistent;
+		client_myds->myconn->set_charset(default_charset, NAMES);
+
+		if (user_attributes != NULL && strlen(user_attributes)) {
+			nlohmann::json j_user_attributes = nlohmann::json::parse(user_attributes);
+			auto default_transaction_isolation = j_user_attributes.find("default-transaction_isolation");
+
+			if (default_transaction_isolation != j_user_attributes.end()) {
+				std::string def_trx_isolation_val =
+					j_user_attributes["default-transaction_isolation"].get<std::string>();
+				mysql_variables.client_set_value(this, SQL_ISOLATION_LEVEL, def_trx_isolation_val.c_str());
+			}
+		}
+
+		l_free(pkt->size,pkt->ptr);
+		client_myds->setDSS_STATE_QUERY_SENT_NET();
+		client_myds->myprot.generate_pkt_OK(true,NULL,NULL,1,0,0,0,0,NULL);
+		client_myds->DSS=STATE_SLEEP;
+		status=WAITING_CLIENT_DATA;
+	} else {
+		l_free(pkt->size,pkt->ptr);
+
+		std::string t_sql_error_msg { "Received unsupported 'COM_RESET_CONNECTION' for session type '%s'" };
+		std::string sql_error_msg {};
+		string_format(t_sql_error_msg, sql_error_msg, proxysql_session_type_str(session_type).c_str());
+
+		client_myds->setDSS_STATE_QUERY_SENT_NET();
+		client_myds->myprot.generate_pkt_ERR(true,NULL,NULL,2,1047,(char *)"28000", sql_error_msg.c_str(), true);
+		client_myds->DSS=STATE_SLEEP;
+		status=WAITING_CLIENT_DATA;
+	}
+}
+
 void MySQL_Session::handler___client_DSS_QUERY_SENT___server_DSS_NOT_INITIALIZED__get_connection() {
 			// Get a MySQL Connection
 
diff --git a/lib/MySQL_Thread.cpp b/lib/MySQL_Thread.cpp
index 3a2584c409..e892333f24 100644
--- a/lib/MySQL_Thread.cpp
+++ b/lib/MySQL_Thread.cpp
@@ -411,7 +411,6 @@ void MySQL_Listeners_Manager::del(unsigned int idx) {
 static char * mysql_thread_variables_names[]= {
 	(char *)"shun_on_failures",
 	(char *)"shun_recovery_time_sec",
-	(char *)"unshun_algorithm",
 	(char *)"query_retries_on_failure",
 	(char *)"client_multi_statements",
 	(char *)"client_host_cache_size",
@@ -1034,7 +1033,6 @@ MySQL_Threads_Handler::MySQL_Threads_Handler() {
 	memset(&variables, 0, sizeof(variables));
 	variables.shun_on_failures=5;
 	variables.shun_recovery_time_sec=10;
-	variables.unshun_algorithm=0;
 	variables.query_retries_on_failure=1;
 	variables.client_multi_statements=true;
 	variables.client_host_cache_size=0;
@@ -1177,7 +1175,7 @@ MySQL_Threads_Handler::MySQL_Threads_Handler() {
 	variables.ssl_p2s_cipher=NULL;
 	variables.ssl_p2s_crl=NULL;
 	variables.ssl_p2s_crlpath=NULL;
-	variables.keep_multiplexing_variables=strdup((char *)"tx_isolation,transaction_isolation,version");
+	variables.keep_multiplexing_variables=strdup((char *)"tx_isolation,version");
 #ifdef DEBUG
 	variables.session_debug=true;
 #endif /*debug */
@@ -2178,7 +2176,6 @@ char ** MySQL_Threads_Handler::get_variables_list() {
 		VariablesPointers_int["reset_connection_algorithm"]  = make_tuple(&variables.reset_connection_algorithm,  1,               2, false);
 		VariablesPointers_int["shun_on_failures"]            = make_tuple(&variables.shun_on_failures,            0,        10000000, false);
 		VariablesPointers_int["shun_recovery_time_sec"]      = make_tuple(&variables.shun_recovery_time_sec,      0,     3600*24*365, false);
-		VariablesPointers_int["unshun_algorithm"]            = make_tuple(&variables.unshun_algorithm,            0,               1, false);
 		VariablesPointers_int["hostgroup_manager_verbose"]   = make_tuple(&variables.hostgroup_manager_verbose,   1,               2, false);
 		VariablesPointers_int["tcp_keepalive_time"]          = make_tuple(&variables.tcp_keepalive_time,          0,            7200, false);
 		VariablesPointers_int["min_num_servers_lantency_awareness"]        = make_tuple(&variables.min_num_servers_lantency_awareness,        0, 10000, false);
@@ -2546,10 +2543,7 @@ void MySQL_Threads_Handler::update_client_host_cache(struct sockaddr* client_soc
 	if (error) {
 		pthread_mutex_lock(&mutex_client_host_cache);
 		// If the cache is full, find the oldest entry on it, and update/remove it.
-		if (
-			mysql_thread___client_host_cache_size &&
-			client_host_cache.size() >= static_cast<size_t>(mysql_thread___client_host_cache_size)
-		) {
+		if (client_host_cache.size() >= static_cast<size_t>(mysql_thread___client_host_cache_size)) {
 			auto older_elem = std::min_element(
 				client_host_cache.begin(),
 				client_host_cache.end(),
@@ -2559,10 +2553,8 @@ void MySQL_Threads_Handler::update_client_host_cache(struct sockaddr* client_soc
 					return f_entry.second.updated_at < s_entry.second.updated_at;
 				}
 			);
-			if (older_elem != client_host_cache.end()) {
-				if (older_elem->first != client_addr) {
-					client_host_cache.erase(older_elem);
-				}
+			if (older_elem->first != client_addr) {
+				client_host_cache.erase(older_elem);
 			}
 		}
 
@@ -3719,9 +3711,7 @@ void MySQL_Thread::process_all_sessions() {
 			if (sess_time/1000 > (unsigned long long)mysql_thread___connect_timeout_client) {
 				proxy_warning("Closing not established client connection %s:%d after %llums\n",sess->client_myds->addr.addr,sess->client_myds->addr.port, sess_time/1000);
 				sess->healthy = 0;
-				if (mysql_thread___client_host_cache_size) {
-					GloMTH->update_client_host_cache(sess->client_myds->client_addr, true);
-				}
+				GloMTH->update_client_host_cache(sess->client_myds->client_addr, true);
 			}
 		}
 		if (maintenance_loop) {
@@ -3839,7 +3829,6 @@ void MySQL_Thread::refresh_variables() {
 	mysql_thread___ping_timeout_server=GloMTH->get_variable_int((char *)"ping_timeout_server");
 	mysql_thread___shun_on_failures=GloMTH->get_variable_int((char *)"shun_on_failures");
 	mysql_thread___shun_recovery_time_sec=GloMTH->get_variable_int((char *)"shun_recovery_time_sec");
-	mysql_thread___unshun_algorithm=GloMTH->get_variable_int((char *)"unshun_algorithm");
 	mysql_thread___query_retries_on_failure=GloMTH->get_variable_int((char *)"query_retries_on_failure");
 	mysql_thread___connect_retries_on_failure=GloMTH->get_variable_int((char *)"connect_retries_on_failure");
 	mysql_thread___client_multi_statements=(bool)GloMTH->get_variable_int((char *)"client_multi_statements");
diff --git a/lib/ProxySQL_Admin.cpp b/lib/ProxySQL_Admin.cpp
index 72ee440ddc..e8537afaa8 100644
--- a/lib/ProxySQL_Admin.cpp
+++ b/lib/ProxySQL_Admin.cpp
@@ -12,7 +12,6 @@
 #include "proxysql.h"
 #include "proxysql_config.h"
 #include "proxysql_restapi.h"
-#include "proxysql_utils.h"
 #include "cpp.h"
 
 #include "MySQL_Data_Stream.h"
@@ -3606,84 +3605,6 @@ void admin_session_handler(MySQL_Session *sess, void *_pa, PtrSize_t *pkt) {
 			}
 		}
 	}
-#ifdef DEBUG
-	/**
-	 * @brief Handles the 'PROXYSQL_SIMULATOR' command. Performing the operation specified in the payload
-	 *   format.
-	 * @details The 'PROXYSQL_SIMULATOR' command is specified the following format. Allowing to perform a
-	 *   certain internal state changing operation. Payload spec:
-	 *   ```
-	 *   PROXYSQL_SIMULATOR ${operation} ${hg} ${address}:${port} ${operation_params}
-	 *   ```
-	 *
-	 *   Supported operations include:
-	 *     - mysql_error: Find the server specified by 'hostname:port' in the specified hostgroup and calls
-	 *       'MySrvC::connect_error()' with the provider 'error_code'.
-	 *
-	 *   Payload example:
-	 *   ```
-	 *   PROXYSQL_SIMULATOR mysql_error 1 127.0.0.1 3306 1234
-	 *   ```
-	 */
-	if (!strncasecmp("PROXYSQL_SIMULATOR ", query_no_space, strlen("PROXYSQL_SIMULATOR "))) {
-		if (sess->session_type == PROXYSQL_SESSION_ADMIN) { // no stats
-			proxy_warning("Received PROXYSQL_SIMULATOR command: %s\n", query_no_space);
-
-			re2::RE2::Options opts = re2::RE2::Options(RE2::Quiet);
-			re2::RE2 pattern("\\s*(\\w+) (\\d+) (\\d+\\.\\d+\\.\\d+\\.\\d+):(\\d+) (\\d+)\\s*\\;*", opts);
-			re2::StringPiece input(query_no_space + strlen("PROXYSQL_SIMULATOR"));
-
-			std::string command, s_hg, srv_addr, s_port, s_errcode {};
-			bool c_res = re2::RE2::Consume(&input, pattern, &command, &s_hg, &srv_addr, &s_port, &s_errcode);
-
-			long i_hg = 0;
-			long i_port = 0;
-			long i_errcode = 0;
-
-			if (c_res == true) {
-				char* endptr = nullptr;
-				i_hg = std::strtol(s_hg.c_str(), &endptr, 10);
-				if (errno == ERANGE || errno == EINVAL) i_hg = LONG_MIN;
-				i_port = std::strtol(s_port.c_str(), &endptr, 10);
-				if (errno == ERANGE || errno == EINVAL) i_port = LONG_MIN;
-				i_errcode = std::strtol(s_errcode.c_str(), &endptr, 10);
-				if (errno == ERANGE || errno == EINVAL) i_errcode = LONG_MIN;
-			}
-
-			if (c_res == true && i_hg != LONG_MIN && i_port != LONG_MIN && i_errcode != LONG_MIN) {
-				MyHGM->wrlock();
-
-				MySrvC* mysrvc = MyHGM->find_server_in_hg(i_hg, srv_addr, i_port);
-				if (mysrvc != nullptr) {
-					int backup_mysql_thread___shun_on_failures = mysql_thread___shun_on_failures;
-					mysql_thread___shun_on_failures = 1;
-
-					// Set the error twice to surpass 'mysql_thread___shun_on_failures' value.
-					mysrvc->connect_error(i_errcode, false);
-					mysrvc->connect_error(i_errcode, false);
-
-					mysql_thread___shun_on_failures = backup_mysql_thread___shun_on_failures;
-
-					SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL);
-				} else {
-					std::string t_err_msg { "Supplied server '%s:%d' wasn't found in hg '%d'" };
-					std::string err_msg {};
-					string_format(t_err_msg, err_msg, srv_addr.c_str(), i_port, i_hg);
-
-					proxy_info("%s\n", err_msg.c_str());
-					SPA->send_MySQL_ERR(&sess->client_myds->myprot, const_cast<char*>(err_msg.c_str()));
-				}
-
-				MyHGM->wrunlock();
-			} else {
-				SPA->send_MySQL_ERR(&sess->client_myds->myprot, (char*)"Invalid arguments supplied with query 'PROXYSQL_SIMULATOR'");
-			}
-
-			run_query=false;
-			goto __run_query;
-		}
-	}
-#endif // DEBUG
 	if (!strncasecmp("PROXYSQLTEST ", query_no_space, strlen("PROXYSQLTEST "))) {
 		if (sess->session_type == PROXYSQL_SESSION_ADMIN) { // no stats
 			int test_n = 0;
@@ -3877,7 +3798,6 @@ void admin_session_handler(MySQL_Session *sess, void *_pa, PtrSize_t *pkt) {
 							run_query=false;
 						}
 						break;
-#ifdef DEBUG
 					case 51:
 						{
 							char msg[256];
@@ -3887,29 +3807,6 @@ void admin_session_handler(MySQL_Session *sess, void *_pa, PtrSize_t *pkt) {
 							run_query=false;
 						}
 						break;
-					case 52:
-						{
-							char msg[256];
-							SPA->mysql_servers_wrlock();
-							SPA->admindb->execute("DELETE FROM mysql_servers WHERE hostgroup_id=5211");
-							SPA->admindb->execute("INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) VALUES (5211,'127.0.0.2',3306,10000)");
-							SPA->admindb->execute("INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) VALUES (5211,'127.0.0.3',3306,8000)");
-							SPA->admindb->execute("INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) VALUES (5211,'127.0.0.4',3306,8000)");
-							SPA->admindb->execute("INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) VALUES (5211,'127.0.0.5',3306,7000)");
-							SPA->load_mysql_servers_to_runtime();
-							SPA->mysql_servers_wrunlock();
-							proxy_debug(PROXY_DEBUG_ADMIN, 4, "Loaded mysql servers to RUNTIME\n");
-							unsigned long long d = SPA->ProxySQL_Test___MySQL_HostGroups_Manager_Balancing_HG5211();
-							sprintf(msg, "Tested in %llums\n", d);
-							SPA->mysql_servers_wrlock();
-							SPA->admindb->execute("DELETE FROM mysql_servers WHERE hostgroup_id=5211");
-							SPA->load_mysql_servers_to_runtime();
-							SPA->mysql_servers_wrunlock();
-							SPA->send_MySQL_OK(&sess->client_myds->myprot, msg, NULL);
-							run_query=false;
-						}
-						break;
-#endif // DEBUG
 					default:
 						SPA->send_MySQL_ERR(&sess->client_myds->myprot, (char *)"Invalid test");
 						run_query=false;
@@ -12709,7 +12606,6 @@ unsigned long long ProxySQL_Admin::ProxySQL_Test___MySQL_HostGroups_Manager_read
 	return d;
 }
 
-#ifdef DEBUG
 // NEVER USED THIS FUNCTION IN PRODUCTION.
 // THIS IS FOR TESTING PURPOSE ONLY
 // IT ACCESSES MyHGM without lock
@@ -12739,51 +12635,3 @@ unsigned long long ProxySQL_Admin::ProxySQL_Test___MySQL_HostGroups_Manager_HG_l
 	unsigned long long d = t2-t1;
 	return d;
 }
-
-// NEVER USED THIS FUNCTION IN PRODUCTION.
-// THIS IS FOR TESTING PURPOSE ONLY
-// IT ACCESSES MyHGM without lock
-unsigned long long ProxySQL_Admin::ProxySQL_Test___MySQL_HostGroups_Manager_Balancing_HG5211() {
-	unsigned long long t1 = monotonic_time();
-	const unsigned int NS = 4;
-	unsigned int cu[NS] = { 50, 10, 10, 0 };
-	unsigned int hid = 0;
-	MyHGC * myhgc = NULL;
-	myhgc = MyHGM->MyHGC_lookup(5211);
-	assert(myhgc);
-	assert(myhgc->mysrvs->servers->len == NS);
-	unsigned int cnt[NS];
-	for (unsigned int i=0; i<NS; i++) {
-		cnt[i]=0;
-	}
-	for (unsigned int i=0; i<NS; i++) {
-		MySrvC * m = (MySrvC *)myhgc->mysrvs->servers->index(i);
-		m->ConnectionsUsed->conns->len=cu[i];
-	}
-	unsigned int NL = 1000;
-	for (unsigned int i=0; i<NL; i++) {
-		MySrvC * mysrvc = myhgc->get_random_MySrvC(NULL, NULL, -1, NULL);
-		assert(mysrvc);
-		for (unsigned int k=0; k<NS; k++) {
-			MySrvC * m = (MySrvC *)myhgc->mysrvs->servers->index(k);
-			if (m == mysrvc)
-				cnt[k]++;
-		}
-	}
-	{
-		unsigned int tc = 0;
-		for (unsigned int k=0; k<NS; k++) {
-			tc += cnt[k];
-		}
-		assert(tc == NL);
-	}
-	for (unsigned int k=0; k<NS; k++) {
-		proxy_info("Balancing_HG5211: server %u, cnt: %u\n", k, cnt[k]);
-	}
-	unsigned long long t2 = monotonic_time();
-	t1 /= 1000;
-	t2 /= 1000;
-	unsigned long long d = t2-t1;
-	return d;
-}
-#endif //DEBUG
diff --git a/lib/ProxySQL_GloVars.cpp b/lib/ProxySQL_GloVars.cpp
index d4cdf76ed1..fd86d43773 100644
--- a/lib/ProxySQL_GloVars.cpp
+++ b/lib/ProxySQL_GloVars.cpp
@@ -50,8 +50,6 @@ void crash_handler(int sig) {
 		}
 		//free(strings); // we don't free, we are crashing anyway
 	}
-	fprintf(stderr, "To report a crashing bug visit: https://github.com/sysown/proxysql/issues\n");
-	fprintf(stderr, "For support visit: https://proxysql.com/services/support/\n");
 
 
 #endif /* __GLIBC__ */
diff --git a/lib/mysql_connection.cpp b/lib/mysql_connection.cpp
index fa4a512c62..bf443000ba 100644
--- a/lib/mysql_connection.cpp
+++ b/lib/mysql_connection.cpp
@@ -2293,25 +2293,23 @@ bool MySQL_Connection::IsKeepMultiplexEnabledVariables(char *query_digest_text)
 	}
 	//filter @@session. and @@
 	char *match=NULL;
-	char* last_pos=NULL;
-	const int at_session_offset = strlen("@@session.");
-	const int double_at_offset = strlen("@@");
 	while (query_digest_text_filter_select && (match = strcasestr(query_digest_text_filter_select,"@@session."))) {
-		memmove(match, match + at_session_offset, strlen(match) - at_session_offset);
-		last_pos = match + strlen(match) - at_session_offset;
-		*last_pos = '\0';
+		*match = '\0';
+		strcat(query_digest_text_filter_select, match+strlen("@@session."));
 	}
 	while (query_digest_text_filter_select && (match = strcasestr(query_digest_text_filter_select,"@@"))) {
-		memmove(match, match + double_at_offset, strlen(match) - double_at_offset);
-		last_pos = match + strlen(match) - double_at_offset;
-		*last_pos = '\0';
+		*match = '\0';
+		if (strlen(query_digest_text_filter_select) == 0) {
+			memcpy(query_digest_text_filter_select, match, strlen("@@"));
+		} else {
+			strcat(query_digest_text_filter_select, match+strlen("@@"));
+		}
 	}
 
 	std::vector<char*>query_digest_text_filter_select_v;
 	char* query_digest_text_filter_select_tok = NULL;
-	char* save_query_digest_text_ptr = NULL;
 	if (query_digest_text_filter_select) {
-		query_digest_text_filter_select_tok = strtok_r(query_digest_text_filter_select, ",", &save_query_digest_text_ptr);
+	query_digest_text_filter_select_tok = strtok(query_digest_text_filter_select, ",");
 	}
 	while(query_digest_text_filter_select_tok){
 		//filter "as"/space/alias,such as select @@version as a, @@version b
@@ -2330,20 +2328,19 @@ bool MySQL_Connection::IsKeepMultiplexEnabledVariables(char *query_digest_text)
 		}else{
 			query_digest_text_filter_select_v.push_back(query_digest_text_filter_select_tok);
 		}
-		query_digest_text_filter_select_tok=strtok_r(NULL, ",", &save_query_digest_text_ptr);
+		query_digest_text_filter_select_tok=strtok(NULL, ",");
 	}
 
 	std::vector<char*>keep_multiplexing_variables_v;
 	char* keep_multiplexing_variables_tmp;
-	char* save_keep_multiplexing_variables_ptr = NULL;
 	unsigned long keep_multiplexing_variables_len=strlen(mysql_thread___keep_multiplexing_variables);
 	keep_multiplexing_variables_tmp=(char*)malloc(keep_multiplexing_variables_len+1);
 	memcpy(keep_multiplexing_variables_tmp, mysql_thread___keep_multiplexing_variables, keep_multiplexing_variables_len);
 	keep_multiplexing_variables_tmp[keep_multiplexing_variables_len]='\0';
-	char* keep_multiplexing_variables_tok=strtok_r(keep_multiplexing_variables_tmp, " ,", &save_keep_multiplexing_variables_ptr);
+	char* keep_multiplexing_variables_tok=strtok(keep_multiplexing_variables_tmp, " ,");
 	while (keep_multiplexing_variables_tok){
 		keep_multiplexing_variables_v.push_back(keep_multiplexing_variables_tok);
-		keep_multiplexing_variables_tok=strtok_r(NULL, " ,", &save_keep_multiplexing_variables_ptr);
+		keep_multiplexing_variables_tok=strtok(NULL, " ,");
 	}
 
 	for (std::vector<char*>::iterator it=query_digest_text_filter_select_v.begin();it!=query_digest_text_filter_select_v.end();it++){
diff --git a/src/main.cpp b/src/main.cpp
index e78cf1d263..2ba2b93033 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1168,7 +1168,7 @@ bool ProxySQL_daemonize_phase2() {
 	//daemon_log(LOG_INFO, "Starting ProxySQL\n");
 	//daemon_log(LOG_INFO, "Sucessfully started");
 	proxy_info("Starting ProxySQL\n");
-	proxy_info("Successfully started\n");
+	proxy_info("Sucessfully started\n");
 	return true;
 }
 
@@ -1464,10 +1464,6 @@ int main(int argc, const char * argv[]) {
 #ifdef DEBUG
 		std::cerr << "WARNING: this is a DEBUG release and can be slow or perform poorly. Do not use it in production" << std::endl;
 #endif
-	proxy_info("For information about products and services visit: https://proxysql.com/\n");
-	proxy_info("For online documentation visit: https://proxysql.com/documentation/\n");
-	proxy_info("For support visit: https://proxysql.com/services/support/\n");
-	proxy_info("For consultancy visit: https://proxysql.com/services/consulting/\n");
 
 	{
 		unsigned int missed_heartbeats = 0;
diff --git a/src/proxy_tls.cpp b/src/proxy_tls.cpp
index 44143b01cb..eff307a117 100644
--- a/src/proxy_tls.cpp
+++ b/src/proxy_tls.cpp
@@ -92,6 +92,67 @@ int callback_ssl_verify_peer(int ok, X509_STORE_CTX* ctx) {
 	return 1;
 }
 
+/*
+
+generated with: $ openssl dhparam -5 -C 2048
+
+-----BEGIN DH PARAMETERS-----
+MIIBCAKCAQEAtS5UPzxesyj7QtLe6hRGE1Cv4TnDbSzKTmy0izFabdn0wR1QVmij
+S8YSb1jE+O7IGImtk84Wg4y141PAHkCMTEeCMKH5tOD0WfiVyuQDTp4Vbt0vOReM
+hK7tgLHLC1P3v0nxFCcce3U6IXmXBQ9IkNMFcXSRIAdBOjPkFPfbZ648qSgcoX+z
+gfEP9WAXeeNGk62rDb3R0mguA9HcQ4NyKk6ETBVsZD4bTAcSIBaX05ISV7qY2eLj
+9HFYBXYX4cxBfMyiqGrCj2IMg8aRKmf7rTvwBQXT0cWmu+kpnlpXIjx6vdpBmeKd
+hSypLEcUVIvzc6rtfWlYKT35wQ+AGKNADwIBBQ==
+-----END DH PARAMETERS-----
+
+*/
+
+
+
+#ifndef HEADER_DH_H
+#include <openssl/dh.h>
+#endif
+DH *get_dh2048()
+	{
+	static unsigned char dh2048_p[]={
+		0xB5,0x2E,0x54,0x3F,0x3C,0x5E,0xB3,0x28,0xFB,0x42,0xD2,0xDE,
+		0xEA,0x14,0x46,0x13,0x50,0xAF,0xE1,0x39,0xC3,0x6D,0x2C,0xCA,
+		0x4E,0x6C,0xB4,0x8B,0x31,0x5A,0x6D,0xD9,0xF4,0xC1,0x1D,0x50,
+		0x56,0x68,0xA3,0x4B,0xC6,0x12,0x6F,0x58,0xC4,0xF8,0xEE,0xC8,
+		0x18,0x89,0xAD,0x93,0xCE,0x16,0x83,0x8C,0xB5,0xE3,0x53,0xC0,
+		0x1E,0x40,0x8C,0x4C,0x47,0x82,0x30,0xA1,0xF9,0xB4,0xE0,0xF4,
+		0x59,0xF8,0x95,0xCA,0xE4,0x03,0x4E,0x9E,0x15,0x6E,0xDD,0x2F,
+		0x39,0x17,0x8C,0x84,0xAE,0xED,0x80,0xB1,0xCB,0x0B,0x53,0xF7,
+		0xBF,0x49,0xF1,0x14,0x27,0x1C,0x7B,0x75,0x3A,0x21,0x79,0x97,
+		0x05,0x0F,0x48,0x90,0xD3,0x05,0x71,0x74,0x91,0x20,0x07,0x41,
+		0x3A,0x33,0xE4,0x14,0xF7,0xDB,0x67,0xAE,0x3C,0xA9,0x28,0x1C,
+		0xA1,0x7F,0xB3,0x81,0xF1,0x0F,0xF5,0x60,0x17,0x79,0xE3,0x46,
+		0x93,0xAD,0xAB,0x0D,0xBD,0xD1,0xD2,0x68,0x2E,0x03,0xD1,0xDC,
+		0x43,0x83,0x72,0x2A,0x4E,0x84,0x4C,0x15,0x6C,0x64,0x3E,0x1B,
+		0x4C,0x07,0x12,0x20,0x16,0x97,0xD3,0x92,0x12,0x57,0xBA,0x98,
+		0xD9,0xE2,0xE3,0xF4,0x71,0x58,0x05,0x76,0x17,0xE1,0xCC,0x41,
+		0x7C,0xCC,0xA2,0xA8,0x6A,0xC2,0x8F,0x62,0x0C,0x83,0xC6,0x91,
+		0x2A,0x67,0xFB,0xAD,0x3B,0xF0,0x05,0x05,0xD3,0xD1,0xC5,0xA6,
+		0xBB,0xE9,0x29,0x9E,0x5A,0x57,0x22,0x3C,0x7A,0xBD,0xDA,0x41,
+		0x99,0xE2,0x9D,0x85,0x2C,0xA9,0x2C,0x47,0x14,0x54,0x8B,0xF3,
+		0x73,0xAA,0xED,0x7D,0x69,0x58,0x29,0x3D,0xF9,0xC1,0x0F,0x80,
+		0x18,0xA3,0x40,0x0F,
+		};
+	static unsigned char dh2048_g[]={
+		0x05,
+		};
+	DH *dh;
+
+	if ((dh=DH_new()) == NULL) return(NULL);
+	dh->p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL);
+	dh->g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL);
+	if ((dh->p == NULL) || (dh->g == NULL))
+		{ DH_free(dh); return(NULL); }
+	return(dh);
+}
+
+
+
 X509 * generate_x509(EVP_PKEY *pkey, const unsigned char *cn, uint32_t serial, int days, X509 *ca_x509, EVP_PKEY *ca_pkey) {
 	int rc;
 	X509 * x = NULL;
@@ -240,6 +301,8 @@ int ssl_mkit(X509 **x509ca, X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial
 	X509 *x2;
 	EVP_PKEY *pk;
 	RSA *rsa;
+	DH *dh;
+	//X509_NAME *name = NULL;
 
 	// relative path to datadir of ssl files
 	const char * ssl_key_rp = (const char *)"proxysql-key.pem";
@@ -372,8 +435,10 @@ int ssl_mkit(X509 **x509ca, X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial
 	*x509p = x2;
 	*pkeyp = pk;
 
+	dh = get_dh2048();
+
 	if (bootstrap == true) {
-		if (SSL_CTX_set_dh_auto(GloVars.global.ssl_ctx, 1) == 0) {
+		if (SSL_CTX_set_tmp_dh(GloVars.global.ssl_ctx, dh) == 0) {
 			proxy_error("Error in SSL while initializing DH: %s . Shutting down.\n",ERR_error_string(ERR_get_error(), NULL));
 			exit(EXIT_SUCCESS); // EXIT_SUCCESS to avoid a restart loop
 		}
@@ -381,9 +446,7 @@ int ssl_mkit(X509 **x509ca, X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial
 		SSL_METHOD *ssl_method;
 		ssl_method = (SSL_METHOD *)TLS_server_method();
 		GloVars.global.tmp_ssl_ctx = SSL_CTX_new(ssl_method);
-
-		if (SSL_CTX_set_dh_auto(GloVars.global.ssl_ctx, 1) == 0) {
-			proxy_error("Error in SSL while initializing DH: %s . Shutting down.\n",ERR_error_string(ERR_get_error(), NULL));
+		if (SSL_CTX_set_tmp_dh(GloVars.global.tmp_ssl_ctx, dh) == 0) {
 			proxy_error("Aborting PROXYSQL RELOAD TLS. Error in SSL while initializing DH: %s\n",ERR_error_string(ERR_get_error(), NULL));
 			msg = "RELOAD TLS failed: Error initializing DH. ";
 			msg += ERR_error_string(ERR_get_error(), NULL);
@@ -402,6 +465,8 @@ int ProxySQL_create_or_load_TLS(bool bootstrap, std::string& msg) {
 
 	int ret = 0;
 
+	CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF);
+
 	bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
 
 	if (bootstrap == true) {


Test patch:
diff --git a/test/tap/tap/Makefile b/test/tap/tap/Makefile
index 9be38ee36b..db8e6d39bd 100644
--- a/test/tap/tap/Makefile
+++ b/test/tap/tap/Makefile
@@ -5,6 +5,16 @@ MARIADB_PATH=$(DEPS_PATH)/mariadb-client-library/mariadb_client
 MARIADB_IDIR=$(MARIADB_PATH)/include
 MARIADB_LDIR=$(MARIADB_PATH)/libmariadb
 
+CURL_DIR=$(DEPS_PATH)/curl/curl
+CURL_IDIR=$(CURL_DIR)/include
+CURL_LDIR=$(CURL_DIR)/lib/.libs
+
+IDIR=../../../include
+LDIR=../../../lib
+
+LIBPROXYSQLAR=$(LDIR)/libproxysql.a
+INCLUDEDIRS=-I$(IDIR) -I$(JSON_IDIR) -I$(MARIADB_IDIR)
+
 .PHONY: all
 all: libtap.a
 
@@ -18,6 +28,6 @@ debug: OPT = -O0 -DDEBUG -ggdb
 debug: libtap.a
 
 libtap.a: tap.cpp tap.h command_line.cpp command_line.h utils.cpp utils.h
-	g++ -c tap.cpp command_line.cpp utils.cpp -std=c++11 -I$(JSON_IDIR) -I$(MARIADB_IDIR) $(OPT)
-	ar rcs libtap.a tap.o command_line.o utils.o
+	g++ -c tap.cpp command_line.cpp utils.cpp -std=c++11 $(INCLUDEDIRS) $(OPT)
+	ar rcs libtap.a tap.o command_line.o utils.o $(LIBPROXYSQLAR)
 
diff --git a/test/tap/tap/utils.cpp b/test/tap/tap/utils.cpp
index f274de6d15..7ef2b5c9f0 100644
--- a/test/tap/tap/utils.cpp
+++ b/test/tap/tap/utils.cpp
@@ -1,19 +1,20 @@
 #include <algorithm>
-#include <chrono>
-#include <cstring>
-#include <fcntl.h>
-#include <iostream>
-#include <numeric>
-#include <memory>
 #include <string>
+#include <cstring>
+#include <mysql.h>
 #include <unistd.h>
 #include <sys/wait.h>
 
-#include <mysql.h>
-
 #include "tap.h"
 #include "utils.h"
 
+#include <unistd.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <iostream>
+
+#include "proxysql_utils.h"
+
 int show_variable(MYSQL *mysql, const std::string& var_name, std::string& var_value) {
 	char query[128];
 
@@ -560,116 +561,106 @@ int wait_until_enpoint_ready(
 	return res;
 }
 
-std::string random_string(std::size_t strSize) {
-	std::string dic { "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" };
-
-	std::random_device rd {};
-	std::mt19937 generator { rd() };
-
-	std::shuffle(dic.begin(), dic.end(), generator);
-
-	if (strSize < dic.size()) {
-		return dic.substr(0, strSize);
-	} else {
-		std::size_t req_modulus = static_cast<std::size_t>(strSize / dic.size());
-		std::size_t req_reminder = strSize % dic.size();
-		std::string random_str {};
-
-		for (std::size_t i = 0; i < req_modulus; i++) {
-			random_str.append(dic);
+MARIADB_CHARSET_INFO * proxysql_find_charset_collate(const char *collatename) {
+	MARIADB_CHARSET_INFO *c = (MARIADB_CHARSET_INFO *)mariadb_compiled_charsets;
+	do {
+		if (!strcasecmp(c->name, collatename)) {
+			return c;
 		}
-
-		random_str.append(dic.substr(0, req_reminder));
-
-		return random_str;
-	}
+		++c;
+	} while (c[0].nr != 0);
+	return NULL;
 }
 
-const double COLISSION_PROB = 1e-8;
-
-int wait_for_replication(
-	MYSQL* proxy, MYSQL* proxy_admin, const std::string& check, uint32_t timeout, uint32_t read_hg
+int create_proxysql_user(
+	MYSQL* proxysql_admin,
+	const std::string& user,
+	const std::string& pass,
+	const std::string& attributes
 ) {
-	if (proxy == NULL) { return EXIT_FAILURE; }
+	std::string t_del_user_query { "DELETE FROM mysql_users WHERE username='%s'" };
+	std::string del_user_query {};
+	string_format(t_del_user_query, del_user_query, user.c_str());
 
-	const std::string t_count_reader_hg_servers {
-		"SELECT COUNT(*) FROM mysql_servers WHERE hostgroup_id=%d"
+	std::string t_insert_user {
+		"INSERT INTO mysql_users (username,password,active,attributes)"
+		" VALUES ('%s','%s',1,'%s')"
 	};
-	std::string count_reader_hg_servers {};
-	size_t size =
-		snprintf( nullptr, 0, t_count_reader_hg_servers.c_str(), read_hg) + 1;
-	{
-		std::unique_ptr<char[]> buf(new char[size]);
-		snprintf(buf.get(), size, t_count_reader_hg_servers.c_str(), read_hg);
-		count_reader_hg_servers = std::string(buf.get(), buf.get() + size - 1);
-	}
-
-	MYSQL_QUERY(proxy_admin, count_reader_hg_servers.c_str());
-	MYSQL_RES* hg_count_res = mysql_store_result(proxy_admin);
-	MYSQL_ROW row = mysql_fetch_row(hg_count_res);
-	uint32_t srv_count = strtoul(row[0], NULL, 10);
-	mysql_free_result(hg_count_res);
-
-	if (srv_count > UINT_MAX) {
-		return EXIT_FAILURE;
-	}
-
-	int waited = 0;
-	int queries = 0;
-	int result = EXIT_FAILURE;
+	std::string insert_user {};
+	string_format(t_insert_user, insert_user, user.c_str(), pass.c_str(), attributes.c_str());
 
-	if (srv_count != 0) {
-		int retries = ceil(log10(COLISSION_PROB) / log10(static_cast<long double>(1)/srv_count));
-		auto start = std::chrono::system_clock::now();
-		std::chrono::duration<double> elapsed {};
+	MYSQL_QUERY(proxysql_admin, del_user_query.c_str());
+	MYSQL_QUERY(proxysql_admin, insert_user.c_str());
 
-		while (elapsed.count() < timeout && queries < retries) {
-			int rc = mysql_query(proxy, check.c_str());
-			bool correct_result = false;
+	return EXIT_SUCCESS;
+}
 
-			if (rc == EXIT_SUCCESS) {
-				MYSQL_RES* st_res = mysql_store_result(proxy);
-				if (st_res) {
-					uint32_t field_num = mysql_num_fields(st_res);
-					uint32_t row_num = mysql_num_rows(st_res);
+int create_mysql_user(
+	MYSQL* mysql_server,
+	const std::string& user,
+	const std::string& pass
+) {
+	const std::string t_drop_user_query { "DROP USER IF EXISTS %s@'%%'" };
+	std::string drop_user_query {};
+	string_format(t_drop_user_query, drop_user_query, user.c_str());
 
-					if (field_num == 1 && row_num == 1) {
-						MYSQL_ROW row = mysql_fetch_row(st_res);
+	const std::string t_create_user_query {
+		"CREATE USER IF NOT EXISTS %s@'%%' IDENTIFIED WITH 'mysql_native_password' BY \"%s\""
+	};
+	std::string create_user_query {};
+	string_format(t_create_user_query, create_user_query, user.c_str(), pass.c_str());
 
-						std::string exp_res { "TRUE" };
-						if (strcasecmp(exp_res.c_str(), row[0]) == 0) {
-							correct_result = true;
-							queries += 1;
-						}
-					}
+	const std::string t_grant_all_query { "GRANT ALL ON *.* TO %s@'%%'" };
+	std::string grant_all_query { };
+	string_format(t_grant_all_query, grant_all_query, user.c_str());
 
-					mysql_free_result(st_res);
-				}
-			} else {
-				diag(
-					"Replication check failed due to query error: ('%d','%s')",
-					mysql_errno(proxy), mysql_error(proxy)
-				);
-			}
+	MYSQL_QUERY(mysql_server, drop_user_query.c_str());
+	MYSQL_QUERY(mysql_server, create_user_query.c_str());
+	MYSQL_QUERY(mysql_server, grant_all_query.c_str());
 
-			if (correct_result == false) {
-				queries = 0;
-				waited += 1;
-				sleep(1);
-			} else {
-				continue;
-			}
+	return EXIT_SUCCESS;
+}
 
-			auto it_end = std::chrono::system_clock::now();
-			elapsed = it_end - start;
+int create_extra_users(
+	MYSQL* proxysql_admin,
+	MYSQL* mysql_server,
+	const std::vector<user_config>& users_config
+) {
+	std::vector<std::pair<std::string, std::string>> v_user_pass {};
+	std::transform(
+		std::begin(users_config),
+		std::end(users_config),
+		std::back_inserter(v_user_pass),
+		[](const user_config& u_config) {
+			return std::pair<std::string, std::string> {
+				std::get<0>(u_config),
+				std::get<1>(u_config)
+			};
 		}
+	);
+
+	// create the MySQL users
+	for (const auto& user_pass : v_user_pass) {
+		int c_user_res =
+			create_mysql_user(mysql_server, user_pass.first, user_pass.second);
+		if (c_user_res) {
+			return c_user_res;
+		}
+	}
 
-		if (queries == retries) {
-			result = EXIT_SUCCESS;
+	// create the ProxySQL users
+	for (const auto& user_config : users_config) {
+		int c_p_user_res =
+			create_proxysql_user(
+				proxysql_admin,
+				std::get<0>(user_config),
+				std::get<1>(user_config),
+				std::get<2>(user_config)
+			);
+		if (c_p_user_res) {
+			return c_p_user_res;
 		}
-	} else {
-		result = EXIT_SUCCESS;
 	}
 
-	return result;
+	return EXIT_SUCCESS;
 }
diff --git a/test/tap/tap/utils.h b/test/tap/tap/utils.h
index 4b95d6364d..12cda5dc86 100644
--- a/test/tap/tap/utils.h
+++ b/test/tap/tap/utils.h
@@ -142,33 +142,56 @@ CURLcode perform_simple_post(
 );
 
 /**
- * @brief Generates a random string of the length of the provider 'strSize'
- *  parameter.
+ * NOTE: This is a duplicate of 'proxysql_find_charset_collate' in 'MySQL_Variables.h'. Including
+ * 'MySQL_Variables' is not a easy task due to its interdependeces with other ProxySQL modules.
+ */
+MARIADB_CHARSET_INFO * proxysql_find_charset_collate(const char *collatename);
+
+/**
+ * @brief Creates the new supplied user in ProxySQL with the provided
+ *   attributes.
  *
- * @param strSize The size of the string to be generated.
- * @return A random string.
+ * @param proxysql_admin An already opened connection to ProxySQL Admin.
+ * @param user The username of the user to be created.
+ * @param pass The password of the user to be created.
+ * @param attributes The 'attributes' value for the 'attributes' column
+ *   for the user to be created.
+ *
+ * @return EXIT_SUCCESS in case of success, EXIT_FAILURE otherwise.
  */
-std::string random_string(std::size_t strSize);
+int create_proxysql_user(
+	MYSQL* proxysql_admin, const std::string& user, const std::string& pass, const std::string& attributes
+);
+
+/**
+ * @brief Create a MySQL user for testing purposes in the server determined
+ *  by supplied *already established* MySQL connection.
+ *
+ * @param mysql_server An already opened connection to a MySQL server.
+ * @param user The name of the user to be created.
+ * @param pass The password for the user to be created.
+ *
+ * @return EXIT_SUCCESS in case of success, EXIT_FAILURE otherwise.
+ */
+int create_mysql_user(MYSQL* mysql_server, const std::string& user, const std::string& pass);
+
+using user_config = std::tuple<std::string, std::string, std::string>;
 
 /**
- * @brief Helper function to wait for replication to complete,
- *   performs a simple supplied queried until it succeed or the
- *   timeout expires.
+ * @brief Create the extra required users for the test in
+ *   both MYSQL and ProxySQL.
  *
- * @param proxy A already opened MYSQL connection to ProxySQL.
- * @param proxy_admin A already opened MYSQL connection to ProxySQL Admin interface.
- * @param check Query to perform until timeout expires. The query is expected to produce
- *   a result with only one ROW and one FIELD containing non-case sensitive strings "TRUE"
- *   or "FALSE". "TRUE" meaning that the replication check succeed.
- * @param timeout The timeout in seconds to retry the query.
- * @param reader_hg The current 'reader hostgroup' for which
- *   servers replication needs to be waited.
+ * @param proxysql_admin An already opened connection to ProxySQL admin
+ *   interface.
+ * @param mysql_server An already opened connection to a backend MySQL
+ *   server.
+ * @param user_attributes The user attributes whose should  be part of user
+ *   configuration in ProxySQL side.
  *
- * @return EXIT_SUCCESS in case of success, EXIT_FAILURE
- *   otherwise.
+ * @return EXIT_SUCCESS in case of success, EXIT_FAILURE otherwise.
  */
-int wait_for_replication(
-	MYSQL* proxy, MYSQL* proxy_admin, const std::string& check, uint32_t timeout, uint32_t reader_hg
+int create_extra_users(
+	MYSQL* proxysql_admin, MYSQL* mysql_server, const std::vector<user_config>& users_config
 );
 
 #endif // #define UTILS_H
diff --git a/test/tap/tests/Makefile b/test/tap/tests/Makefile
index f6c5d74e8c..597878dc22 100644
--- a/test/tap/tests/Makefile
+++ b/test/tap/tests/Makefile
@@ -132,8 +132,5 @@ test_admin_prometheus_metrics_dump-t: test_admin_prometheus_metrics_dump-t.cpp $
 create_connection_annotation: test_connection_annotation-t.cpp
 	g++ -DTEST_AURORA -DDEBUG test_connection_annotation-t.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 $(OBJ) $(MYLIBS) -ltap -ldl $(STATIC_LIBS) -o test_connection_annotation-t -DGITVERSION=\"$(GIT_VERSION)\"
 
-test_set_collation-t: test_set_collation-t.cpp $(TAP_LIBDIR)/libtap.a
-	g++ test_set_collation-t.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 $(MYLIBS) -ltap -Wl,--no-as-needed -ldl -lpthread -o test_set_collation-t -DGITVERSION=\"$(GIT_VERSION)\"
-
 setparser_test: setparser_test.cpp $(TAP_LIBDIR)/libtap.a $(RE2_PATH)/util/test.cc $(LDIR)/set_parser.cpp $(LIBPROXYSQLAR)
 	g++ -DDEBUG setparser_test.cpp $(RE2_PATH)/util/test.cc ../../../src/obj/proxysql_global.o $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 -lproxysql $(MYLIBS) -ltap -ldl -lpthread $(WASAN) -o setparser_test -DGITVERSION=\"$(GIT_VERSION)\"
diff --git a/test/tap/tests/admin_various_commands2-t.cpp b/test/tap/tests/admin_various_commands2-t.cpp
index 3f3b73da73..b37e39d6a2 100644
--- a/test/tap/tests/admin_various_commands2-t.cpp
+++ b/test/tap/tests/admin_various_commands2-t.cpp
@@ -166,7 +166,7 @@ int main() {
 
 
 	for (std::vector<std::string>::iterator it2 = queries.begin(); it2 != queries.end(); it2++) {
-		MYSQL* proxysql_admin = mysql_init(NULL); // local scope
+		proxysql_admin = mysql_init(NULL); // local scope
 		if (!proxysql_admin) {
 			fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_admin));
 			return -1;
diff --git a/test/tap/tests/client_host_err/create_netns_n.sh b/test/tap/tests/client_host_err/create_netns_n.sh
index 0d12ae49a1..4128030d6a 100755
--- a/test/tap/tests/client_host_err/create_netns_n.sh
+++ b/test/tap/tests/client_host_err/create_netns_n.sh
@@ -1,9 +1,4 @@
 #!/bin/bash
-
-# NOTE: This script is currently unused, but it's left here because it's useful
-# for creating network namespaces in a easy way. It could be of use for future
-# testing.
-
 if [[ $EUID -ne 0 ]]; then
    echo "This script must be run as root"
    exit 1
diff --git a/test/tap/tests/client_host_err/delete_netns_n.sh b/test/tap/tests/client_host_err/delete_netns_n.sh
index 19ace75d15..80dfbcc5fc 100755
--- a/test/tap/tests/client_host_err/delete_netns_n.sh
+++ b/test/tap/tests/client_host_err/delete_netns_n.sh
@@ -1,9 +1,4 @@
 #!/bin/bash
-
-# NOTE: This script is currently unused, but it's left here because it's useful
-# for deleting network namespaces in a easy way. It could be of use for future
-# testing.
-
 if [[ $EUID -ne 0 ]]; then
    echo "This script must be run as root"
    exit 1
diff --git a/test/tap/tests/firewall_commands1-t.cpp b/test/tap/tests/firewall_commands1-t.cpp
index f3bfd1a631..51611e434a 100644
--- a/test/tap/tests/firewall_commands1-t.cpp
+++ b/test/tap/tests/firewall_commands1-t.cpp
@@ -85,7 +85,7 @@ int main() {
 	plan(queries.size());
 
 	for (std::vector<std::string>::iterator it2 = queries.begin(); it2 != queries.end(); it2++) {
-		MYSQL* proxysql_admin = mysql_init(NULL); // local scope . We intentionally create new connections
+		proxysql_admin = mysql_init(NULL); // local scope . We intentionally create new connections
 		if (!proxysql_admin) {
 			fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_admin));
 			return -1;
diff --git a/test/tap/tests/mysql-mirror1-t.cpp b/test/tap/tests/mysql-mirror1-t.cpp
index 42e00c8726..2c4a3f9b2d 100644
--- a/test/tap/tests/mysql-mirror1-t.cpp
+++ b/test/tap/tests/mysql-mirror1-t.cpp
@@ -127,8 +127,6 @@ int main(int argc, char** argv) {
 	}
 	int rows_read = 0;
 
-	sleep(1); // some INSERT may still be running
-
 	// at this point the table sbtest should have 600 rows:
 	// 300 rows from normal insert, and 100 rows from mirror
 	rc = run_q(conns[0], "SELECT * FROM test.sbtest1");
diff --git a/test/tap/tests/reg_test_1574-stmt_metadata-t.cpp b/test/tap/tests/reg_test_1574-stmt_metadata-t.cpp
index 5f8743d9ee..a6eca44bdc 100644
--- a/test/tap/tests/reg_test_1574-stmt_metadata-t.cpp
+++ b/test/tap/tests/reg_test_1574-stmt_metadata-t.cpp
@@ -94,7 +94,7 @@ int main(int argc, char** argv) {
 	}
 
 	// Force the 'hostgroup' for the 'SELECT' query to avoid replication issues
-	std::string query_t = "SELECT /* ;hostgroup=0,%s */ * FROM test.reg_test_1574";
+	std::string query_t = "SELECT /*+ ;hostgroup=0,%s */ * FROM test.reg_test_1574";
 	std::string query (static_cast<std::size_t>(query_t.size() + 20), '\0');
 
 	std::string rnd_str(static_cast<std::size_t>(20), '\0');
diff --git a/test/tap/tests/reg_test_3317-lock_hostgroup_special_queries-t.cpp b/test/tap/tests/reg_test_3317-lock_hostgroup_special_queries-t.cpp
index 46264349c1..71f041fe48 100644
--- a/test/tap/tests/reg_test_3317-lock_hostgroup_special_queries-t.cpp
+++ b/test/tap/tests/reg_test_3317-lock_hostgroup_special_queries-t.cpp
@@ -33,7 +33,7 @@ void check_set_names(MYSQL* proxysql_mysql) {
 		return;
 	}
 
-	query_res = mysql_query(proxysql_mysql, "SELECT /* ;hostgroup=0 */ @@character_set_client, @@character_set_results, @@character_set_connection");
+	query_res = mysql_query(proxysql_mysql, "SELECT /*+ ;hostgroup=0 */ @@character_set_client, @@character_set_results, @@character_set_connection");
 	if (query_res) {
 		diag("Query failed with error: %s", mysql_error(proxysql_mysql));
 		return;
@@ -77,7 +77,7 @@ void check_set_names(MYSQL* proxysql_mysql) {
  * @param proxysql_mysql A MYSQL handle to an already stablished MySQL connection.
  */
 void check_autocommit(MYSQL* proxysql_mysql) {
-	int query_res = mysql_query(proxysql_mysql, "SELECT /* ;hostgroup=0 */ @@autocommit");
+	int query_res = mysql_query(proxysql_mysql, "SELECT /*+ ;hostgroup=0 */ @@autocommit");
 	if (query_res) {
 		diag("Query failed with error: %s", mysql_error(proxysql_mysql));
 		return;
@@ -104,7 +104,7 @@ void check_autocommit(MYSQL* proxysql_mysql) {
 	}
 
 	// Check new status on @@autocommit
-	query_res = mysql_query(proxysql_mysql, "SELECT /* ;hostgroup=0 */ @@autocommit");
+	query_res = mysql_query(proxysql_mysql, "SELECT /*+ ;hostgroup=0 */ @@autocommit");
 	if (query_res) {
 		diag("Query failed with error: %s", mysql_error(proxysql_mysql));
 		return;
@@ -139,7 +139,7 @@ void check_session_character_set_server(MYSQL* proxysql_mysql) {
 		return;
 	}
 
-	query_res = mysql_query(proxysql_mysql, "SELECT /* ;hostgroup=0 */ @@character_set_server");
+	query_res = mysql_query(proxysql_mysql, "SELECT /*+ ;hostgroup=0 */ @@character_set_server");
 	if (query_res) {
 		diag("Query failed with error: %s", mysql_error(proxysql_mysql));
 		return;
@@ -178,7 +178,7 @@ void check_session_character_set_results(MYSQL* proxysql_mysql) {
 		return;
 	}
 
-	query_res = mysql_query(proxysql_mysql, "SELECT /* ;hostgroup=0 */ @@character_set_results");
+	query_res = mysql_query(proxysql_mysql, "SELECT /*+ ;hostgroup=0 */ @@character_set_results");
 	if (query_res) {
 		diag("Query failed with error: %s", mysql_error(proxysql_mysql));
 		return;
diff --git a/test/tap/tests/reg_test_3427-stmt_first_comment1-t.cpp b/test/tap/tests/reg_test_3427-stmt_first_comment1-t.cpp
index e59c166dcf..91bed356e5 100644
--- a/test/tap/tests/reg_test_3427-stmt_first_comment1-t.cpp
+++ b/test/tap/tests/reg_test_3427-stmt_first_comment1-t.cpp
@@ -77,6 +77,7 @@ int main(int argc, char** argv) {
 		}
 	}
 
+	MYSQL_STMT* stmt = nullptr;
 	MYSQL* proxysql_mysql = mysql_init(NULL);
 	MYSQL* proxysql_admin = mysql_init(NULL);
 
@@ -90,6 +91,13 @@ int main(int argc, char** argv) {
 		return -1;
 	}
 
+	stmt = mysql_stmt_init(proxysql_mysql);
+	if (!stmt) {
+		diag("mysql_stmt_init(), out of memory");
+		res = EXIT_FAILURE;
+		goto exit;
+	}
+
 	// Insert data in the table to be queried
 	// *************************************************************************
 
@@ -148,21 +156,14 @@ int main(int argc, char** argv) {
 			std::string query_t {};
 
 			if (param) {
-				query_t = "SELECT /* ;hostgroup=0;%d */ * FROM test.reg_test_3427 WHERE id IN (?)";
+				query_t = "SELECT /*+ ;hostgroup=0;%d */ * FROM test.reg_test_3427 WHERE id IN (?)";
 			} else {
-				query_t = "SELECT /* ;hostgroup=0;%d */ * FROM test.reg_test_3427";
+				query_t = "SELECT /*+ ;hostgroup=0;%d */ * FROM test.reg_test_3427";
 			}
 
 			std::string query {};
 			string_format(query_t, query, query_id);
 
-			MYSQL_STMT* stmt = mysql_stmt_init(proxysql_mysql);
-			if (!stmt) {
-				diag("mysql_stmt_init(), out of memory");
-				res = EXIT_FAILURE;
-				goto exit;
-			}
-
 			if (mysql_stmt_prepare(stmt, query.c_str(), strlen(query.c_str()))) {
 				diag("mysql_stmt_prepare at line %d failed: %s", __LINE__ , mysql_error(proxysql_mysql));
 				mysql_close(proxysql_mysql);
@@ -260,12 +261,11 @@ int main(int argc, char** argv) {
 				res = EXIT_FAILURE;
 				goto exit;
 			}
-
-			mysql_stmt_close(stmt);
 		}
 	}
 
 exit:
+	if (stmt) { mysql_stmt_close(stmt); }
 	mysql_close(proxysql_mysql);
 	mysql_close(proxysql_admin);
 
diff --git a/test/tap/tests/reg_test_3434-text_stmt_mix-t.cpp b/test/tap/tests/reg_test_3434-text_stmt_mix-t.cpp
index b232ab5c27..1d5437e751 100644
--- a/test/tap/tests/reg_test_3434-text_stmt_mix-t.cpp
+++ b/test/tap/tests/reg_test_3434-text_stmt_mix-t.cpp
@@ -221,7 +221,7 @@ std::string build_random_select_query(
 ) {
 	// Force the 'hostgroup' for the 'SELECT' query
 	std::string t_query {
-		"SELECT /* ;hostgroup=%d,%s */ * FROM %s WHERE id IN ("
+		"SELECT /*+ ;hostgroup=%d,%s */ * FROM %s WHERE id IN ("
 	};
 
 	for (uint32_t i = 0; i < num_params; i++) {
diff --git a/test/tap/tests/reg_test_3493-USE_with_comment-t.cpp b/test/tap/tests/reg_test_3493-USE_with_comment-t.cpp
index 9ae2251088..1e45ca19af 100644
--- a/test/tap/tests/reg_test_3493-USE_with_comment-t.cpp
+++ b/test/tap/tests/reg_test_3493-USE_with_comment-t.cpp
@@ -90,19 +90,19 @@ int test_use_queries(MYSQL* proxysql_mysql, bool enabled_digests) {
 		// statement.
 		switch (i%5) {
 			case 0:
-				MYSQL_QUERY(proxysql_mysql, "/* ;create_new_connection=1 */ SELECT DATABASE()");
+				MYSQL_QUERY(proxysql_mysql, "/*+ ;create_new_connection=1 */ SELECT DATABASE()");
 				break;
 			case 1:
-				MYSQL_QUERY(proxysql_mysql, "/* ;create_new_connection=1 */SELECT DATABASE()");
+				MYSQL_QUERY(proxysql_mysql, "/*+ ;create_new_connection=1 */SELECT DATABASE()");
 				break;
 			case 2:
-				MYSQL_QUERY(proxysql_mysql, "SELECT /* ;create_new_connection=1 */ DATABASE()");
+				MYSQL_QUERY(proxysql_mysql, "SELECT /*+ ;create_new_connection=1 */ DATABASE()");
 				break;
 			case 3:
-				MYSQL_QUERY(proxysql_mysql, "SELECT/* ;create_new_connection=1 */ DATABASE()");
+				MYSQL_QUERY(proxysql_mysql, "SELECT/*+ ;create_new_connection=1 */ DATABASE()");
 				break;
 			case 4:
-				MYSQL_QUERY(proxysql_mysql, "SELECT /* ;create_new_connection=1 */DATABASE()");
+				MYSQL_QUERY(proxysql_mysql, "SELECT /*+ ;create_new_connection=1 */DATABASE()");
 				break;
 			default:
 				assert(0);
diff --git a/test/tap/tests/reg_test_3546-stmt_empty_params-t.cpp b/test/tap/tests/reg_test_3546-stmt_empty_params-t.cpp
index 82c0e3323f..2f07ca1647 100644
--- a/test/tap/tests/reg_test_3546-stmt_empty_params-t.cpp
+++ b/test/tap/tests/reg_test_3546-stmt_empty_params-t.cpp
@@ -47,7 +47,7 @@ int prepare_stmt(
 ) {
 	int res = EXIT_SUCCESS;
 	std::string query {
-		"SELECT /* ;hostgroup=0 */ id,c1,c2 FROM test.reg_test_3546 WHERE date IN (?)"
+		"SELECT /*+ ;hostgroup=0 */ id,c1,c2 FROM test.reg_test_3546 WHERE date IN (?)"
 	};
 
 	if (mysql_stmt_prepare(stmt, query.c_str(), strlen(query.c_str()))) {
@@ -89,6 +89,7 @@ int main(int argc, char** argv) {
 		return -1;
 	}
 
+	MYSQL_STMT* stmt_param = nullptr;
 	MYSQL* proxysql_mysql = mysql_init(NULL);
 	MYSQL* proxysql_admin = mysql_init(NULL);
 
@@ -102,6 +103,12 @@ int main(int argc, char** argv) {
 		return -1;
 	}
 
+	stmt_param = mysql_stmt_init(proxysql_mysql);
+	if (!stmt_param) {
+		diag("mysql_stmt_init(), out of memory");
+		goto exit;
+	}
+
 	// Insert the row to be queried with the prepared statement.
 	// *************************************************************************
 	MYSQL_QUERY(proxysql_mysql, "CREATE DATABASE IF NOT EXISTS test");
@@ -125,13 +132,6 @@ int main(int argc, char** argv) {
 	}
 
 	{
-		MYSQL_STMT* stmt_param = nullptr;
-		stmt_param = mysql_stmt_init(proxysql_mysql);
-		if (!stmt_param) {
-			diag("mysql_stmt_init(), out of memory");
-			goto exit;
-		}
-
 		// Set the number of maximum connections for servers in the writer hostgroup
 		std::string t_update_mysql_servers {
 			"UPDATE mysql_servers SET max_connections=1 WHERE hostgroup_id=%d"
@@ -246,11 +246,10 @@ int main(int argc, char** argv) {
 				);
 			}
 		}
-
-		mysql_stmt_close(stmt_param);
 	}
 
 exit:
+	if (stmt_param) { mysql_stmt_close(stmt_param); }
 	mysql_close(proxysql_mysql);
 	mysql_close(proxysql_admin);
 
diff --git a/test/tap/tests/reg_test_3549-autocommit_tracking-t.cpp b/test/tap/tests/reg_test_3549-autocommit_tracking-t.cpp
index d035c691e1..5243c78411 100644
--- a/test/tap/tests/reg_test_3549-autocommit_tracking-t.cpp
+++ b/test/tap/tests/reg_test_3549-autocommit_tracking-t.cpp
@@ -138,19 +138,19 @@ std::vector<std::pair<std::string, test_spec>> test_definitions {
 		"simple_set_autocommit_no_lock",
 		{
 			{ "SET autocommit=1",             1 },
-			{ "SELECT /* ;hostgroup=0 */ 1",  1 },
+			{ "SELECT /*+ ;hostgroup=0 */ 1", 1 },
 			{ "SET autocommit=0",             0 },
-			{ "SELECT /* ;hostgroup=0 */ 1",  0 }
+			{ "SELECT /*+ ;hostgroup=0 */ 1", 0 }
 		}
 	},
 	{
 		"simple_set_autocommit_no_lock_2",
 		{
 			{ "SET autocommit=0",             0 },
-			{ "SELECT /* ;hostgroup=0 */ 1",  0 },
+			{ "SELECT /*+ ;hostgroup=0 */ 1", 0 },
 			{ "COMMIT",                       0 },
 			{ "SET autocommit=1",             1 },
-			{ "SELECT /* ;hostgroup=0 */ 1", 1 }
+			{ "SELECT /*+ ;hostgroup=0 */ 1", 1 }
 		}
 	},
 	{
@@ -158,9 +158,9 @@ std::vector<std::pair<std::string, test_spec>> test_definitions {
 		{
 			{ "SET @session_var=1",           1 },
 			{ "SET autocommit=1",             1 },
-			{ "SELECT /* ;hostgroup=0 */ 1",  1 },
+			{ "SELECT /*+ ;hostgroup=0 */ 1", 1 },
 			{ "SET autocommit=0",             0 },
-			{ "SELECT /* ;hostgroup=0 */ 1",  0 }
+			{ "SELECT /*+ ;hostgroup=0 */ 1", 0 }
 		}
 	},
 	{
@@ -168,10 +168,10 @@ std::vector<std::pair<std::string, test_spec>> test_definitions {
 		{
 			{ "SET @session_var=1",           1 },
 			{ "SET autocommit=0",             0 },
-			{ "SELECT /* ;hostgroup=0 */ 1",  0 },
+			{ "SELECT /*+ ;hostgroup=0 */ 1", 0 },
 			{ "COMMIT",                       0 },
 			{ "SET autocommit=1",             1 },
-			{ "SELECT /* ;hostgroup=0 */ 1",  1 }
+			{ "SELECT /*+ ;hostgroup=0 */ 1", 1 }
 		}
 	},
 	{
@@ -181,19 +181,19 @@ std::vector<std::pair<std::string, test_spec>> test_definitions {
 		"complex_set_autocommit_no_lock_1",
 		{
 			{ "SET time_zone='+04:00', character_set_client='latin1', max_join_size=10000, autocommit=1", 1 },
-			{ "SELECT /* ;hostgroup=0 */ 1",                                                              1 },
+			{ "SELECT /*+ ;hostgroup=0 */ 1",                                                             1 },
 			{ "SET time_zone='+04:00', character_set_client='latin1', max_join_size=10000, autocommit=0", 0 },
-			{ "SELECT /* ;hostgroup=0 */ 1",                                                              0 }
+			{ "SELECT /*+ ;hostgroup=0 */ 1",                                                             0 }
 		}
 	},
 	{
 		"complex_set_autocommit_no_lock_2",
 		{
 			{ "SET time_zone='+04:00', character_set_client='latin1', max_join_size=10000, autocommit=0", 0 },
-			{ "SELECT /* ;hostgroup=0 */ 1",                                                              0 },
+			{ "SELECT /*+ ;hostgroup=0 */ 1",                                                             0 },
 			{ "COMMIT",                                                                                   0 },
 			{ "SET time_zone='+04:00', character_set_client='latin1', max_join_size=10000, autocommit=1", 1 },
-			{ "SELECT /* ;hostgroup=0 */ 1",                                                              1 }
+			{ "SELECT /*+ ;hostgroup=0 */ 1",                                                             1 }
 		}
 	},
 	{
@@ -201,9 +201,9 @@ std::vector<std::pair<std::string, test_spec>> test_definitions {
 		{
 			{ "SET @session_var=1",                                                                       1 },
 			{ "SET time_zone='+04:00', character_set_client='latin1', max_join_size=10000, autocommit=1", 1 },
-			{ "SELECT /* ;hostgroup=0 */ 1",                                                              1 },
+			{ "SELECT /*+ ;hostgroup=0 */ 1",                                                             1 },
 			{ "SET time_zone='+04:00', character_set_client='latin1', max_join_size=10000, autocommit=0", 0 },
-			{ "SELECT /* ;hostgroup=0 */ 1",                                                              0 }
+			{ "SELECT /*+ ;hostgroup=0 */ 1",                                                             0 }
 		}
 	},
 	{
@@ -211,26 +211,26 @@ std::vector<std::pair<std::string, test_spec>> test_definitions {
 		{
 			{ "SET @session_var=1",                                                                       1 },
 			{ "SET time_zone='+04:00', character_set_client='latin1', max_join_size=10000, autocommit=0", 0 },
-			{ "SELECT /* ;hostgroup=0 */ 1",                                                              0 },
+			{ "SELECT /*+ ;hostgroup=0 */ 1",                                                             0 },
 			{ "COMMIT",                                                                                   0 },
 			{ "SET time_zone='+04:00', character_set_client='latin1', max_join_size=10000, autocommit=1", 1 },
-			{ "SELECT /* ;hostgroup=0 */ 1",                                                              1 }
+			{ "SELECT /*+ ;hostgroup=0 */ 1",                                                             1 }
 		}
 	},
 	{
 		"mix_set_autocommit_1",
 		{
 			{ "SET time_zone='+04:00', character_set_client='latin1', max_join_size=10000, autocommit=0", 0 },
-			{ "SELECT /* ;hostgroup=0 */ 1",                                                              0 },
+			{ "SELECT /*+ ;hostgroup=0 */ 1",                                                             0 },
 			{ "COMMIT",                                                                                   0 },
 			{ "SET time_zone='+04:00', character_set_client='latin1', max_join_size=10000, autocommit=1", 1 },
-			{ "SELECT /* ;hostgroup=0 */ 1",                                                              1 },
+			{ "SELECT /*+ ;hostgroup=0 */ 1",                                                             1 },
 			{ "SET autocommit=0",                                                                         0 },
 			{ "COMMIT",                                                                                   0 },
 			{ "SET autocommit=1",                                                                         1 },
 			{ "BEGIN",                                                                                    1 },
 			{ "SET @session_var=1",                                                                       1 },
-			{ "SELECT /* ;hostgroup=0 */ 1",                                                              1 },
+			{ "SELECT /*+ ;hostgroup=0 */ 1",                                                             1 },
 			{ "COMMIT",                                                                                   1 },
 		}
 	},
@@ -238,16 +238,16 @@ std::vector<std::pair<std::string, test_spec>> test_definitions {
 		"mix_set_autocommit_2",
 		{
 			{ "SET time_zone='+04:00', character_set_client='latin1', max_join_size=10000, autocommit=0", 0 },
-			{ "SELECT /* ;hostgroup=0 */ 1",                                                              0 },
+			{ "SELECT /*+ ;hostgroup=0 */ 1",                                                             0 },
 			{ "COMMIT",                                                                                   0 },
 			{ "SET time_zone='+04:00', character_set_client='latin1', max_join_size=10000, autocommit=1", 1 },
-			{ "SELECT /* ;hostgroup=0 */ 1",                                                              1 },
+			{ "SELECT /*+ ;hostgroup=0 */ 1",                                                             1 },
 			{ "SET autocommit=0",                                                                         0 },
-			{ "SELECT /* ;hostgroup=0 */ 1",                                                              0 },
+			{ "SELECT /*+ ;hostgroup=0 */ 1",                                                             0 },
 			{ "COMMIT",                                                                                   0 },
 			{ "BEGIN",                                                                                    0 },
 			{ "SET @session_var=1",                                                                       0 },
-			{ "SELECT /* ;hostgroup=0 */ 1",                                                              0 },
+			{ "SELECT /*+ ;hostgroup=0 */ 1",                                                             0 },
 			{ "COMMIT",                                                                                   0 },
 		}
 	},
diff --git a/test/tap/tests/reg_test_3585-stmt_metadata-t.cpp b/test/tap/tests/reg_test_3585-stmt_metadata-t.cpp
index c6a19cb872..3e78a049ec 100644
--- a/test/tap/tests/reg_test_3585-stmt_metadata-t.cpp
+++ b/test/tap/tests/reg_test_3585-stmt_metadata-t.cpp
@@ -348,7 +348,7 @@ int main(int argc, char** argv) {
 	int rc;
 	std::string query_i = "INSERT INTO test.reg_test_3585 VALUES (? , ? , ? , ? , ? , ? , ?)";
 	// Force the 'hostgroup' for the 'SELECT' query to avoid replication issues
-	std::string query_s = "SELECT /* ;hostgroup=0 */ * FROM test.reg_test_3585 WHERE id=?";
+	std::string query_s = "SELECT /*+ ;hostgroup=0 */ * FROM test.reg_test_3585 WHERE id=?";
 
 	// init and prepare INSERT
 	MYSQL_STMT *stmti = mysql_stmt_init(proxysql_mysql);
diff --git a/test/tap/tests/reg_test_3603-stmt_metadata-t.cpp b/test/tap/tests/reg_test_3603-stmt_metadata-t.cpp
index 1f4eb5b693..e116142da4 100644
--- a/test/tap/tests/reg_test_3603-stmt_metadata-t.cpp
+++ b/test/tap/tests/reg_test_3603-stmt_metadata-t.cpp
@@ -555,7 +555,7 @@ int main(int argc, char** argv) {
 			"start_time=?,trck_num=? where id=?";
 
 	// Force the 'hostgroup' for the 'SELECT' query to avoid replication issues
-	std::string query_s = "SELECT /* ;hostgroup=0 */ * FROM test.reg_test_3603 WHERE id=?";
+	std::string query_s = "SELECT /*+ ;hostgroup=0 */ * FROM test.reg_test_3603 WHERE id=?";
 
 	// init and prepare INSERT
 	MYSQL_STMT *stmti = mysql_stmt_init(proxysql_mysql);
diff --git a/test/tap/tests/reg_test_3606-mysql_warnings-t.cpp b/test/tap/tests/reg_test_3606-mysql_warnings-t.cpp
deleted file mode 100644
index 412bc68b61..0000000000
--- a/test/tap/tests/reg_test_3606-mysql_warnings-t.cpp
+++ /dev/null
@@ -1,570 +0,0 @@
-/**
- * @file reg_test_3606_mysql_warnings-t.cpp
- * @brief Regression test that performs multiple queries against a MySQL table
- *   with 'mysql-log_mysql_warnings_enabled' feature enabled. The issued queries are known
- *   to generate MySQL warnings thus providing a regression test for issue #3606.
- * @details Test covers the following cases:
- *   * Mixed prepared statements and text protocol queries are executed correctly when
- *     'mysql-log_mysql_warnings_enabled' is enabled.
- *   * Mixed queries generating warnings and not are correctly executed.
- *   * Multistatements queries mixed with the previous ones are also properly executed.
- */
-
-#include <algorithm>
-#include <unistd.h>
-#include <vector>
-#include <tuple>
-#include <cstring>
-#include <string>
-#include <stdio.h>
-
-#include <mysql.h>
-#include <mysql/mysqld_error.h>
-
-#include <proxysql_utils.h>
-
-#include "tap.h"
-#include "command_line.h"
-#include "utils.h"
-#include "utils.h"
-
-using std::vector;
-using std::tuple;
-using std::string;
-
-enum query_type {
-	TEXT_SELECT_WARNING = 0,
-	TEXT_SELECT_NO_WARNING,
-	TEXT_MULTISTATEMENT_SELECT_WARNING,
-	TEXT_INSERT_WARNING,
-	TEXT_UPDATE_WARNING,
-	TEXT_UPDATE_NO_WARNING
-};
-
-std::vector<std::string> queries {
-	"SELECT /*+ ;hostgroup=0 */ * FROM test.reg_test_3606_mysql_warnings WHERE id=%d",
-	"SELECT * FROM test.reg_test_3606_mysql_warnings WHERE id=%d",
-	"SELECT /*+ ;hostgroup=0 */ * FROM test.reg_test_3606_mysql_warnings WHERE id=%d; SELECT /*+ ;hostgroup=0 */ * FROM test.reg_test_3606_mysql_warnings WHERE id=%d;",
-	"INSERT /*+ ;hostgroup=0 */ INTO test.reg_test_3606_mysql_warnings (a, c, pad) VALUES ('%d', '%s', '%s')",
-	"UPDATE /*+ ;hostgroup=0 */ test.reg_test_3606_mysql_warnings SET a=%d, c='%s', pad='%s' WHERE id=%d",
-	"UPDATE test.reg_test_3606_mysql_warnings SET a=%d, c='%s', pad='%s' WHERE id=%d"
-};
-
-enum stmt_query_type {
-	STMT_SELECT_NO_WARNING = 0,
-	STMT_INSERT_WARNING,
-	STMT_UPDATE_WARNING
-};
-
-std::vector<std::string> stmt_queries {
-	"SELECT /*+ ;hostgroup=0 */ id, a, c, pad FROM test.reg_test_3606_mysql_warnings WHERE id=?",
-	"INSERT /*+ ;hostgroup=0 */ INTO test.reg_test_3606_mysql_warnings (a, c, pad) VALUES (?, ?, ?)",
-	"UPDATE /*+ ;hostgroup=0 */ test.reg_test_3606_mysql_warnings SET a=?, c=?, pad=? WHERE id=?"
-};
-
-int create_testing_tables(MYSQL* mysql_server) {
-	// Create the testing database
-	mysql_query(mysql_server, "CREATE DATABASE IF NOT EXISTS test");
-	mysql_query(mysql_server, "DROP TABLE IF EXISTS test.reg_test_3606_mysql_warnings");
-
-	mysql_query(
-		mysql_server,
-		"CREATE TABLE IF NOT EXISTS test.reg_test_3606_mysql_warnings ("
-		"  id INTEGER NOT NULL AUTO_INCREMENT,"
-		"  a TINYINT NOT NULL,"
-		"  c varchar(255),"
-		"  pad CHAR(60),"
-		"  PRIMARY KEY (id)"
-		")"
-	);
-
-	return mysql_errno(mysql_server);
-}
-
-int main(int argc, char** argv) {
-	CommandLine cl;
-
-	uint32_t c_operations = 500;
-
-	double plan_val =
-		1.0 + // Table creation
-		(double)c_operations + // Initial table filling insert queries
-		floor(((double)c_operations - 1.0) * (1.0 / 4.0) * 3.0) + // Number of reguarl selects checks
-		floor(((double)c_operations - 1.0) * (1.0 / 8.0) * 3.0) + // Number of non-multistatement select checks
-		floor(((double)c_operations - 1.0) * (1.0 / 8.0) * 5.0) + // Number of multistatements select checks
-		floor(((double)c_operations - 1.0) * (1.0 / 2.0));  // Number of updates checks
-	plan(plan_val);
-
-	if (cl.getEnv()) {
-		diag("Failed to get the required environmental variables.");
-		return EXIT_FAILURE;
-	}
-
-	MYSQL* proxy_mysql = mysql_init(NULL);
-	MYSQL* proxy_admin = mysql_init(NULL);
-
-	// Initialize connections
-	if (!proxy_mysql) {
-		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxy_mysql));
-		return EXIT_FAILURE;
-	}
-	if (!proxy_admin) {
-		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxy_admin));
-		return EXIT_FAILURE;
-	}
-
-	if (
-		!mysql_real_connect(proxy_mysql, cl.host, cl.username, cl.password, NULL, cl.port, NULL,
-			CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS)
-	) {
-		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxy_mysql));
-		return EXIT_FAILURE;
-	}
-
-	if (!mysql_real_connect(proxy_admin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) {
-		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxy_admin));
-		return EXIT_FAILURE;
-	}
-
-	MYSQL_QUERY(proxy_admin, "SET mysql-log_mysql_warnings_enabled='true'");
-	MYSQL_QUERY(proxy_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-
-	MYSQL_QUERY(proxy_mysql, "SET sql_mode=ANSI");
-
-	int c_err = create_testing_tables(proxy_mysql);
-	ok(c_err == 0, "Table creation should succeed. ErrCode: %d", c_err);
-	if (tests_failed()) {
-		std::string error = mysql_error(proxy_mysql);
-		diag("MySQL Error: '%s'", error.c_str());
-
-		return exit_status();
-	}
-
-	vector<tuple<int, string, string>> stored_pairs {};
-
-	// Include one initial null element to make index match
-	stored_pairs.push_back(tuple<int, string, string>{0,"", ""});
-	srand(time(NULL));
-
-	for (auto i = 0; i < c_operations; i++) {
-		std::string rnd_c = random_string(rand() % 80 + 1);
-		std::string rnd_pad = random_string(rand() % 15 + 1);
-		const std::string& t_insert_query = queries[TEXT_INSERT_WARNING];
-		std::string insert_query {};
-
-		// Store the random generated strings
-		stored_pairs.push_back(tuple<int, string, string>{ 300, rnd_c, rnd_pad });
-
-		// Execute the INSERT queries
-		string_format(t_insert_query, insert_query, 300, rnd_c.c_str(), rnd_pad.c_str());
-		int i_res = mysql_query(proxy_mysql, insert_query.c_str());
-		uint64_t i_err = mysql_errno(proxy_mysql);
-
-		ok(i_err == 0, "Insert queries should be executed correctly. ErrCode: %ld", i_err);
-		if (tests_failed()) {
-			std::string error = mysql_error(proxy_mysql);
-			diag("MySQL Error: '%s'", error.c_str());
-
-			return exit_status();
-		}
-	}
-
-	const std::string rep_check_query {
-		"SELECT CASE WHEN (SELECT COUNT(*) FROM test.reg_test_3606_mysql_warnings) = 500 THEN 'TRUE' ELSE 'FALSE' END"
-	};
-	int wait_res = wait_for_replication(proxy_mysql, proxy_admin, rep_check_query, 10, 1);
-	if (wait_res != EXIT_SUCCESS) {
-		diag("Waiting for replication failed... Exiting");
-		return EXIT_FAILURE;
-	}
-
-	// Prepare STMT queries
-	std::vector<MYSQL_STMT*> stmts {};
-	for (std::size_t i = 0; i < stmt_queries.size(); i++) {
-		MYSQL_STMT* stmt = mysql_stmt_init(proxy_mysql);
-		if (stmt == nullptr) {
-			diag(
-				"'mysql_stmt_init' failed for 'SELECT' with err: ('%s','%s')",
-				stmt_queries[STMT_SELECT_NO_WARNING].c_str(), mysql_error(proxy_mysql)
-			);
-			return EXIT_FAILURE;
-		}
-		stmts.push_back(stmt);
-	}
-
-	// Prepare SELECT
-	{
-		int err = mysql_stmt_prepare(
-			stmts[0], stmt_queries[STMT_SELECT_NO_WARNING].c_str(), stmt_queries[STMT_SELECT_NO_WARNING].size()
-		);
-		if (err != EXIT_SUCCESS) {
-			diag(
-				"'mysql_stmt_prepare' failed for 'SELECT' with err: ('%s','%s')",
-				stmt_queries[STMT_SELECT_NO_WARNING].c_str(), mysql_error(proxy_mysql)
-			);
-			return EXIT_FAILURE;
-		}
-	}
-	// Prepare UPDATE
-	{
-		int err = mysql_stmt_prepare(
-			stmts[2], stmt_queries[STMT_UPDATE_WARNING].c_str(), stmt_queries[STMT_UPDATE_WARNING].size()
-		);
-		if (err != EXIT_SUCCESS) {
-			diag(
-				"'mysql_stmt_prepare' failed for 'SELECT' with err: ('%s','%s')", stmt_queries[0].c_str(),
-				mysql_error(proxy_mysql)
-			);
-			return EXIT_FAILURE;
-		}
-	}
-
-	bool multistatement = true;
-	bool select_stmt_query = true;
-	bool update_stmt_query = true;
-
-	for (auto id = 1; id < c_operations; id++) {
-		int64_t op = id % 2;
-		int64_t produce_warning = rand() % 2;
-
-		if (op == 0) { // Do a random SELECT
-			if (select_stmt_query) {
-				diag("Performing 'STMT SELECT' query...");
-
-				MYSQL_BIND bindsi[1];
-				memset(bindsi, 0, sizeof(bindsi));
-				int copyid = id;
-
-				bindsi[0].buffer_type= MYSQL_TYPE_LONG;
-				bindsi[0].buffer= (char *)&copyid;
-				bindsi[0].is_null= 0;
-				bindsi[0].length= 0;
-
-				int rc = mysql_stmt_bind_param(stmts[0], bindsi);
-				if (rc) {
-					diag(
-						"'mysql_stmt_bind_param' failed for 'SELECT' with err: ('%s','%s')",
-						stmt_queries[STMT_SELECT_NO_WARNING].c_str(), mysql_error(proxy_mysql)
-					);
-					return EXIT_FAILURE;
-				}
-
-				MYSQL_BIND binds[4];
-				memset(binds, 0, sizeof(binds));
-
-				int64_t id_res;
-				int res_a;
-				char res_c_buf[256];
-				char res_pad_buf[256];
-				memset(res_c_buf, 0, sizeof(res_c_buf));
-				memset(res_pad_buf, 0, sizeof(res_pad_buf));
-
-				unsigned long length[4] = { 0 };
-				my_bool is_null[4] = { 0 };
-				my_bool error[4] = { 0 };
-
-				binds[0].buffer_type= MYSQL_TYPE_LONGLONG;
-				binds[0].buffer= (char *)&id_res;
-				binds[0].is_null= &is_null[0];
-				binds[0].length= &length[0];
-				binds[0].error= &error[0];
-
-				binds[1].buffer_type= MYSQL_TYPE_LONG;
-				binds[1].buffer= (char *)&res_a;
-				binds[1].is_null= &is_null[3];
-				binds[1].length= &length[3];
-				binds[1].error= &error[3];
-
-				binds[2].buffer_type= MYSQL_TYPE_VAR_STRING;
-				binds[2].buffer= (char *)res_c_buf;
-				binds[2].buffer_length= sizeof(res_c_buf);
-				binds[2].is_null= &is_null[1];
-				binds[2].length= &length[1];
-				binds[2].error= &error[1];
-
-				binds[3].buffer_type= MYSQL_TYPE_VAR_STRING;
-				binds[3].buffer= (char *)res_pad_buf;
-				binds[3].buffer_length= sizeof(res_pad_buf);
-				binds[3].is_null= &is_null[2];
-				binds[3].length= &length[2];
-				binds[3].error= &error[2];
-
-				rc = mysql_stmt_execute(stmts[0]);
-				ok(
-					rc == 0, "Select queries should be executed correctly. Err: ('%s', '%d')",
-					mysql_error(proxy_mysql), mysql_errno(proxy_mysql)
-				);
-
-				if (rc) {
-					diag(
-						"'mysql_stmt_execute' failed for 'SELECT' with err: ('%s','%s')",
-						stmt_queries[STMT_SELECT_NO_WARNING].c_str(), mysql_error(proxy_mysql)
-					);
-					return EXIT_FAILURE;
-				}
-
-				rc = mysql_stmt_bind_result(stmts[0], binds);
-				if (rc) {
-					diag(
-						"'mysql_stmt_execute' failed for 'SELECT' with err: ('%s','%s')",
-						stmt_queries[STMT_SELECT_NO_WARNING].c_str(), mysql_error(proxy_mysql)
-					);
-					return EXIT_FAILURE;
-				}
-
-				MYSQL_RES *prepare_meta_result;
-				prepare_meta_result = mysql_stmt_result_metadata(stmts[0]);
-				if (prepare_meta_result == NULL) {
-					diag("mysql_stmt_result_metadata() failed: %s", mysql_stmt_error(stmts[0]));
-					return EXIT_FAILURE;
-				}
-
-				rc = mysql_stmt_store_result(stmts[0]);
-				if (rc) {
-					diag("mysql_stmt_store_result() failed: %s", mysql_stmt_error(stmts[0]));
-					return EXIT_FAILURE;
-				}
-
-				unsigned long long row_count= mysql_stmt_num_rows(stmts[0]);
-				uint32_t field_count= mysql_stmt_field_count(stmts[0]);
-				ok(
-					field_count == 4 && row_count == 1,
-					"Received resulset should have: Exp - ['field_count'='3','row_count'='1'],"
-					" Actual: ['field_count'='%d','row_count'='%lld'].",
-					field_count, row_count
-				);
-
-				rc = mysql_stmt_fetch(stmts[0]);
-				if (rc && rc != MYSQL_DATA_TRUNCATED) {
-					diag("mysql_stmt_fetch() failed: ('%d','%s')", rc, mysql_stmt_error(stmts[0]));
-					return EXIT_FAILURE;
-				}
-
-				bool same_a = std::get<0>(stored_pairs[id]) == 300 && 127 == res_a;
-				bool same_c = std::get<1>(stored_pairs[id]) == std::string { res_c_buf };
-				bool same_pad = std::get<2>(stored_pairs[id]) == std::string { res_pad_buf };
-
-				ok(
-					same_a && same_c && same_pad,
-					"Received 'a', 'c' and 'pad' matches expected values."
-					" ('a': '%d') == ('exp_a': '%d'), ('c': '%s') == ('exp_c': '%s'), ('pad': '%s') == ('exp_pad': '%s')",
-					res_a, 127, res_c_buf, std::get<1>(stored_pairs[id]).c_str(),
-					res_pad_buf, std::get<2>(stored_pairs[id]).c_str()
-				);
-
-				mysql_stmt_free_result(stmts[0]);
-				mysql_free_result(prepare_meta_result);
-
-				if (tests_failed()) {
-					diag("Failed, aborting further tests...");
-					goto cleanup;
-				}
-			} else {
-				if (multistatement) {
-					diag("Performing 'TEXT PROTOCOL MULTISTATEMENT SELECT' query...");
-				} else {
-					diag("Performing 'TEXT PROTOCOL SELECT' query...");
-				}
-
-				std::string t_select_query {};
-				std::string select_query {};
-
-				if (multistatement) {
-					t_select_query = queries[TEXT_MULTISTATEMENT_SELECT_WARNING];
-					string_format(t_select_query, select_query, id, id);
-				} else {
-					if (produce_warning) {
-						t_select_query = queries[TEXT_SELECT_WARNING];
-					} else {
-						t_select_query = queries[TEXT_SELECT_NO_WARNING];
-					}
-					string_format(t_select_query, select_query, id);
-				}
-
-				int rc = mysql_query(proxy_mysql, select_query.c_str());
-				ok(
-					rc == 0, "Select queries should be executed correctly. Err: ('%s', '%d')",
-					mysql_error(proxy_mysql), mysql_errno(proxy_mysql)
-				);
-				if (rc != 0) {
-					diag("Failed, aborting further tests...");
-					goto cleanup;
-				}
-
-				const auto check_result = [&](MYSQL_RES* select_res) -> bool {
-					int field_count = mysql_field_count(proxy_mysql);
-					int row_count = mysql_num_rows(select_res);
-
-					ok(
-						field_count == 4 && row_count == 1,
-							"Received resulset should have: Exp - ['field_count'='3','row_count'='1'],"
-							" Actual: ['field_count'='%d','row_count'='%d'].",
-							field_count, row_count
-					);
-
-					if (tests_failed()) {
-						return false;
-					}
-
-					MYSQL_ROW row = mysql_fetch_row(select_res);
-					bool same_a = std::get<0>(stored_pairs[id]) == 300 && 127 == std::atoi(row[1]);
-					bool same_c = std::get<1>(stored_pairs[id]) == row[2];
-					bool same_pad = std::get<2>(stored_pairs[id]) == row[3];
-
-					ok(
-						same_a && same_c && same_pad,
-						"Received 'a', 'c' and 'pad' matches expected values."
-						" ('a': '%d') == ('exp_a': '%d'), ('c': '%s') == ('exp_c': '%s'), ('pad': '%s') == ('exp_pad': '%s')",
-						std::atoi(row[1]), 127, row[2], std::get<1>(stored_pairs[id]).c_str(), row[3],
-						std::get<2>(stored_pairs[id]).c_str()
-					);
-
-					return tests_failed() == 0;
-				};
-
-				// Check that the SELECT resultset isn't illformed
-				int next_result = 0;
-				int result_count = 0;
-				while(next_result == 0) {
-					result_count++;
-
-					MYSQL_RES* select_res = mysql_store_result(proxy_mysql);
-					bool check_res = check_result(select_res);
-					mysql_free_result(select_res);
-					if (check_res == false) {
-						diag("Failed, aborting further tests...");
-						goto cleanup;
-					}
-					next_result = mysql_next_result(proxy_mysql);
-				}
-
-				if (tests_failed()) {
-					diag("Failed, aborting further tests...");
-					goto cleanup;
-				}
-
-				// Next iteration perform the opposite operation
-				multistatement = !multistatement;
-			}
-
-			// Next iteration perform the opposite operation
-			select_stmt_query = !select_stmt_query;
-		} else { // Do a random UPDATE
-			if (update_stmt_query) {
-				diag("Performing 'STMT UPDATE' query...");
-
-				MYSQL_BIND binds_u[4];
-				memset(binds_u, 0, sizeof(binds_u));
-				unsigned long length[4] = { 0 };
-
-				int64_t id_param = id;
-				int param_a = 99;
-
-				if (produce_warning) {
-					param_a = 255;
-				}
-
-				std::string param_c { random_string(rand() % 100 + 5) };
-				std::string param_pad { random_string(rand() % 60 + 5) };
-
-				unsigned long param_c_len = param_c.size();
-				unsigned long param_pad_len = param_pad.size();
-
-				my_bool is_null[4] = { 0 };
-
-				binds_u[0].buffer_type= MYSQL_TYPE_LONG;
-				binds_u[0].buffer= (char *)&param_a;
-				binds_u[0].is_null= 0;
-				binds_u[0].length= 0;
-
-				binds_u[1].buffer_type= MYSQL_TYPE_VAR_STRING;
-				binds_u[1].buffer= (char *)param_c.c_str();
-				binds_u[1].buffer_length= param_c.size();
-				binds_u[1].is_null= 0;
-				binds_u[1].length= &param_c_len;
-
-				binds_u[2].buffer_type= MYSQL_TYPE_VAR_STRING;
-				binds_u[2].buffer= (char *)param_pad.c_str();
-				binds_u[2].buffer_length= param_pad.size();
-				binds_u[2].is_null= 0;
-				binds_u[2].length= &param_pad_len;
-
-				binds_u[3].buffer_type= MYSQL_TYPE_LONGLONG;
-				binds_u[3].buffer= (char *)&id_param;
-				binds_u[3].is_null= 0;
-				binds_u[3].length= &length[0];
-
-				int rc = mysql_stmt_bind_param(stmts[2], binds_u);
-				if (rc) {
-					diag(
-						"'mysql_stmt_bind_param' failed for 'SELECT' with err: ('%s','%s')",
-						stmt_queries[STMT_UPDATE_WARNING].c_str(), mysql_stmt_error(stmts[2])
-					);
-					return EXIT_FAILURE;
-				}
-
-				rc = mysql_stmt_execute(stmts[2]);
-				if (rc) {
-					diag(
-						"'mysql_stmt_execute' failed for 'SELECT' with err: ('%s','%s')",
-						stmt_queries[STMT_UPDATE_WARNING].c_str(), mysql_error(proxy_mysql)
-					);
-
-					goto cleanup;
-				}
-
-				int affected_rows= mysql_stmt_affected_rows(stmts[2]);
-				ok(
-					rc == 0 && affected_rows == 1,
-					"Update queries should be executed correctly. ErrCode: %d", mysql_stmt_errno(stmts[2])
-				);
-
-				if (tests_failed()) {
-					diag("Failed, aborting further tests...");
-					goto cleanup;
-				}
-			} else {
-				diag("Performing 'TEXT PROTOCOL UPDATE' query...");
-
-				std::string rnd_c = random_string(rand() % 100 + 5);
-				std::string rnd_pad = random_string(rand() % 60 + 5);
-
-				// Store the new random generated strings
-				std::tuple<int, std::string, std::string> new_values { 255, rnd_c, rnd_pad };
-				stored_pairs[id] = new_values;
-
-				std::string update_query {};
-
-				if (produce_warning) {
-					const std::string& t_update_query = queries[TEXT_UPDATE_WARNING];
-					string_format(t_update_query, update_query, 300, rnd_c.c_str(), rnd_pad.c_str(), id);
-				} else {
-					const std::string& t_update_query = queries[TEXT_UPDATE_NO_WARNING];
-					string_format(t_update_query, update_query, 100, rnd_c.c_str(), rnd_pad.c_str(), id);
-				}
-				int u_res = mysql_query(proxy_mysql, update_query.c_str());
-
-				ok(
-					u_res == 0, "Update queries should be executed correctly. ErrCode: %d",
-					mysql_errno(proxy_mysql)
-				);
-				if (tests_failed()) {
-					diag("Failed, aborting further tests...");
-					goto cleanup;
-				}
-			}
-
-			// Next iteration perform the opposite operation
-			update_stmt_query = !update_stmt_query;
-		}
-	}
-cleanup:
-
-	for (MYSQL_STMT* stmt : stmts) {
-		mysql_stmt_close(stmt);
-	}
-	mysql_close(proxy_mysql);
-	mysql_close(proxy_admin);
-
-	return exit_status();
-}
diff --git a/test/tap/tests/reg_test_fast_forward_split_packet-t.cpp b/test/tap/tests/reg_test_fast_forward_split_packet-t.cpp
deleted file mode 100644
index a302543202..0000000000
--- a/test/tap/tests/reg_test_fast_forward_split_packet-t.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/**
- * @file reg_test_fast_forward_split_packet-t.cpp
- * @brief This is a simple regression test for checking that 'FAST_FORWARD' is able to handle split packets
- *   received in a connection that is yet in 'CONNECTING_SERVER' state.
- * @details In order to achieve this behavior consistently, the test performs the following operations:
- *  1. Enables 'fast_forward' for 'mysql_users'.
- *  2. Creates a number of connections.
- *  3. Performs a unique 'INSERT' query of increasing size in each of the connections.
- *
- *  If the issue is present and ProxySQL cannot handle this situation, the test can fail before reaching
- *  'QUEUE_T_DEFAULT_SIZE', but will for sure fail after this threshold is reached. Since the input buffer
- *  is filled by the query, there won't be other option that processing the received packet in two different
- *  iterations of 'MySQL_Session::handler', which will force the 'CONNECTING_SERVER' situation.
- */
-
-#include <vector>
-#include <string>
-#include <stdio.h>
-#include <cstring>
-#include <unistd.h>
-#include <mysql.h>
-
-#include "tap.h"
-#include "command_line.h"
-#include "utils.h"
-
-const int NUM_CONNS = 35;
-
-MYSQL* conns[NUM_CONNS];
-
-int main(int argc, char** argv) {
-	CommandLine cl;
-
-	if (cl.getEnv()) {
-		diag("Failed to get the required environmental variables.");
-		return -1;
-	}
-
-	// One query that should succeed per-connection
-	plan(NUM_CONNS);
-
-	MYSQL* proxysql_admin = mysql_init(NULL);
-	if (!proxysql_admin) {
-		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_admin));
-		return -1;
-	}
-
-	if (!mysql_real_connect(proxysql_admin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) {
-		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_admin));
-		return -1;
-	}
-
-	MYSQL_QUERY(proxysql_admin, "UPDATE mysql_users SET fast_forward=1");
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL USERS TO RUNTIME");
-
-	std::random_device rd {};
-	std::mt19937 mt(rd());
-	std::uniform_int_distribution<int> dist(0.0, 9.0);
-
-	for (int i = 0; i < NUM_CONNS ; i++) {
-		MYSQL * mysql = mysql_init(NULL);
-		if (!mysql) {
-			fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(mysql));
-			return EXIT_FAILURE;
-		}
-
-		if (!mysql_real_connect(mysql, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) {
-			fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(mysql));
-			return EXIT_FAILURE;
-		}
-		conns[i] = mysql;
-	}
-
-	MYSQL_QUERY(conns[0], "DROP TABLE IF EXISTS test.reg_test_fast_forward_split");
-	MYSQL_QUERY(
-		conns[0],
-		"CREATE TABLE IF NOT EXISTS test.reg_test_fast_forward_split ("
-			" `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `k` int(10) unsigned NOT NULL DEFAULT '0',"
-			" `c` char(120) NOT NULL DEFAULT '', `pad` char(60) NOT NULL DEFAULT '',"
-			"  PRIMARY KEY (`id`), KEY `k_1` (`k`) "
-		")"
-	);
-
-	int query_num = 10;
-	std::string q { "INSERT INTO test.reg_test_fast_forward_split (k, c, pad) values " };
-	bool put_comma=false;
-
-	for (int j = 0; j < NUM_CONNS; j++) {
-		MYSQL* proxysql_mysql = conns[j];
-
-		for (int i=0; i< query_num; ++i) {
-			int k = dist(mt);
-			std::string c;
-			for (int j=0; j<10; j++) {
-				for (int k=0; k<11; k++) {
-					c += std::to_string(dist(mt));
-				}
-				if (j<9)
-					c += "-";
-			}
-			std::string pad;
-			for (int j=0; j<5; j++) {
-				for (int k=0; k<11; k++) {
-					pad += std::to_string(dist(mt));
-				}
-				if (j<4)
-					pad += "-";
-			}
-			if (put_comma) q += ",";
-			if (!put_comma) put_comma=true;
-
-			q += "(" + std::to_string(k) + ",'" + c + "','" + pad + "')";
-		}
-
-		int q_err = mysql_query(proxysql_mysql, q.c_str());
-		ok(q_err == EXIT_SUCCESS, "Executing query of size: '%ld', should succeed", q.size());
-	}
-
-	for (int j = 0; j < NUM_CONNS; j++) {
-		mysql_close(conns[j]);
-	}
-
-	mysql_close(proxysql_admin);
-
-	return exit_status();
-}
diff --git a/test/tap/tests/test_client_limit_error-t.cpp b/test/tap/tests/test_client_limit_error-t.cpp
deleted file mode 100644
index ecc158bab9..0000000000
--- a/test/tap/tests/test_client_limit_error-t.cpp
+++ /dev/null
@@ -1,948 +0,0 @@
-/**
- * @file test_client_limit_error.cpp
- * @brief This test aims to verify the logic for the 'client_limit_error' feature.
- *   NOTE: This test isn't executed automatically because it requires elevated privileges
- *   for being able to run the scripts 'create_netns_n' and 'delete_netns_n' that creates
- *   and delete the networks namespaces required for it.
- *
- * @details Right now the test verifies the following cases:
- *  1. Enable the feature and checks that the error count is incremented when a single
- *     client tries to connect and that the cache entry values match expected ones.
- *  2. Flush the entries, and check that counting is performed properly for a
- *     single cache entry.
- *  3. Flush the entries, and check that counting is performed properly for
- *     multiple cache entries.
- *  4. Flush the entries, and check:
- *       1. That counting is performed properly for multiple cache entries.
- *       2. Connections fail after the limit for one client.
- *       3. Clients are deleted after a succesfull connection is performed.
- *  5. Flush the entries, fill the cache and check that when the
- *  'mysql-client_host_error_counts' is changed at runtime, connections are denied
- *  to a client exceeding the new limit.
- *  6. Flush the entries, fill the cache and check that the when the
- *  'mysql-client_host_cache_size' is changed at runtime:
- *    1. The exceeding elements are cleaned with each new connection.
- *    2. Check that is not relevant if the element was or not present
- *       in the cache.
- *    3. Checks that a proper connection is performed succesfully and the element is
- *    removed from the cache
- *  7. Flush the entries and checks that client connections timeouts interact with the
- *    cache in the same way as regular client connection errors.
- *
- * @date 2021-09-10
- */
-
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <signal.h>
-#include <pthread.h>
-#include <stdio.h>
-
-#include <atomic>
-#include <algorithm>
-#include <tuple>
-#include <vector>
-#include <string>
-#include <thread>
-#include <iostream>
-#include <fstream>
-
-#include <libconfig.h>
-#include <proxysql_utils.h>
-#include <mysql.h>
-
-#include "json.hpp"
-#include "tap.h"
-#include "command_line.h"
-#include "utils.h"
-
-const uint32_t NUM_LOOPBACK_ADDRS = 5;
-
-using host_cache_entry = std::tuple<std::string, uint32_t, uint64_t>;
-
-inline unsigned long long monotonic_time() {
-  struct timespec ts;
-  clock_gettime(CLOCK_MONOTONIC, &ts);
-  return (((unsigned long long) ts.tv_sec) * 1000000) + (ts.tv_nsec / 1000);
-}
-
-std::vector<host_cache_entry> get_client_host_cache_entries(MYSQL* proxysql_admin) {
-	int rc = mysql_query(
-		proxysql_admin,
-		"SELECT * FROM stats.stats_mysql_client_host_cache ORDER BY client_address"
-	);
-
-	MYSQL_ROW row = NULL;
-	MYSQL_RES* proxy_res = mysql_store_result(proxysql_admin);
-	std::vector<host_cache_entry> host_cache_entries {};
-
-	while ((row = mysql_fetch_row(proxy_res))) {
-		std::string client_address = row[0];
-		uint32_t error_count = atoi(row[1]);
-		uint64_t last_update = atoll(row[2]);
-
-		host_cache_entries.push_back({client_address, error_count, last_update});
-	}
-
-	mysql_free_result(proxy_res);
-
-	return host_cache_entries;
-}
-
-int invalid_proxysql_conn(const std::string& addr, const CommandLine& cl) {
-	MYSQL* proxysql = mysql_init(NULL);
-	int my_err = EXIT_SUCCESS;
-
-	if (!mysql_real_connect(proxysql, addr.c_str(), "limit_inv_user", "limit_inv_pass", NULL, 6033, NULL, 0)) {
-		my_err = mysql_errno(proxysql);
-	}
-
-	mysql_close(proxysql);
-
-	return my_err;
-}
-
-int invalid_proxysql_conn(const std::string& addr, const CommandLine& cl, std::string& err_msg) {
-	MYSQL* proxysql = mysql_init(NULL);
-	int my_err = EXIT_SUCCESS;
-
-	if (!mysql_real_connect(proxysql, addr.c_str(), "limit_inv_user", "limit_inv_pass", NULL, 6033, NULL, 0)) {
-		my_err = mysql_errno(proxysql);
-		err_msg = mysql_error(proxysql);
-	}
-
-	mysql_close(proxysql);
-
-	return my_err;
-}
-
-int valid_proxysql_conn(const std::string& addr, const CommandLine& cl, std::string& err_msg) {
-	MYSQL* proxysql = mysql_init(NULL);
-	int my_err = EXIT_SUCCESS;
-
-	if (!mysql_real_connect(proxysql, addr.c_str(), cl.username, cl.password, NULL, 6033, NULL, 0)) {
-		my_err = mysql_errno(proxysql);
-		err_msg = mysql_error(proxysql);
-	}
-
-	mysql_close(proxysql);
-
-	return my_err;
-}
-
-/**
- * @brief Enable the feature check that error count is incremented when a
- * new client fails to connect, and that the cache entry values are the
- * expected ones.
- *
- * @param cl CommandLine info for connection creation.
- * @param proxysql_admin An already oppened connection to ProxySQL Admin.
- *
- * @return 'EXIT_SUCCESS' in case of success, 'EXIT_FAILURE' otherwise.
- */
-int test_cache_filled_by_invalid_conn(const CommandLine& cl, MYSQL* proxysql_admin) {
-	diag("                 START TEST NUMBER 1                         ");
-	diag("-------------------------------------------------------------");
-
-	MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_cache_size=1");
-	MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_error_counts=5");
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-
-	// There shouldn't be any other entries in the cache for this test.
-	MYSQL_QUERY(proxysql_admin, "PROXYSQL FLUSH MYSQL CLIENT HOSTS");
-
-	uint64_t pre_command_time = monotonic_time();
-	const std::string exp_client_addr { "127.0.0.2" };
-
-	diag("Performing connection to fill 'client_host_cache'");
-	int inv_user_errno = invalid_proxysql_conn(exp_client_addr, cl);
-	if (inv_user_errno == EXIT_SUCCESS) {
-		diag("Expected failure but client connection succeed");
-		return EXIT_FAILURE;
-	}
-
-	diag("Performing checks over 'client_host_cache'");
-	std::vector<host_cache_entry> entries = get_client_host_cache_entries(proxysql_admin);
-
-	ok(
-		entries.size() == 1,
-		"'client_host_cache' entries should be '1' after issuing 'PROXYSQL FLUSH"
-		" MYSQL CLIENT HOSTS' and one failed connection."
-	);
-
-	if (entries.size() == 1) {
-		host_cache_entry unique_entry { entries.back() };
-		const std::string client_addr { std::get<0>(unique_entry) };
-		const uint32_t error_count { std::get<1>(unique_entry) };
-		const uint64_t last_updated { std::get<2>(unique_entry) };
-		uint64_t post_command_time = monotonic_time();
-
-		ok(
-			client_addr == exp_client_addr && error_count == 1 && (pre_command_time < last_updated < post_command_time),
-			"Entry should match expected values - exp(addr: %s, err_count: %d, last_updated: %ld < %ld < %ld),"
-			" act(addr: %s, err_count: %d, last_updated: %ld < %ld < %ld)",
-			exp_client_addr.c_str(), 1, pre_command_time, last_updated, post_command_time, client_addr.c_str(), error_count,
-			pre_command_time, last_updated, post_command_time
-		);
-	}
-
-	return EXIT_SUCCESS;
-}
-
-/**
- * @brief Flush the entries, and check that counting is performed properly for a single cache entry.
- *
- * @param cl CommandLine info for connection creation.
- * @param proxysql_admin An already oppened connection to ProxySQL Admin.
- *
- * @return 'EXIT_SUCCESS' in case of success, 'EXIT_FAILURE' otherwise.
- */
-int test_cache_entry_count_by_invalid_conn(const CommandLine& cl, MYSQL* proxysql_admin) {
-	printf("\n");
-	diag("                 START TEST NUMBER 2                         ");
-	diag("-------------------------------------------------------------");
-
-	// There shouldn't be any other entries in the cache for this test.
-	MYSQL_QUERY(proxysql_admin, "PROXYSQL FLUSH MYSQL CLIENT HOSTS");
-	int errors = 0;
-	const std::string exp_client_addr { "127.0.0.2" };
-	uint64_t pre_command_time = monotonic_time();
-
-	diag("Performing connection to fill 'client_host_cache'");
-	for (errors = 0; errors < 5; errors++) {
-		int inv_user_errno = invalid_proxysql_conn(exp_client_addr, cl);
-		if (inv_user_errno == EXIT_SUCCESS) {
-			diag("Expected failure but client connection succeed");
-			return EXIT_FAILURE;
-		}
-	}
-
-	diag("Performing checks over 'client_host_cache'");
-	std::vector<host_cache_entry> entries =
-		get_client_host_cache_entries(proxysql_admin);
-
-	ok(
-		entries.size() == 1,
-		"'client_host_cache' entries should be '1' after issuing 'PROXYSQL FLUSH"
-		" MYSQL CLIENT HOSTS' and one failed connection."
-	);
-
-	if (entries.size() == 1) {
-		host_cache_entry unique_entry { entries.back() };
-		const std::string client_addr { std::get<0>(unique_entry) };
-		const uint32_t error_count { std::get<1>(unique_entry) };
-		const uint64_t last_updated { std::get<2>(unique_entry) };
-		uint64_t post_command_time = monotonic_time();
-
-		ok(
-			client_addr == exp_client_addr && error_count == errors &&
-			(pre_command_time < last_updated < post_command_time),
-			"Entry should match expected values - exp(addr: %s, err_count: %d, last_updated: %ld < %ld < %ld),"
-			" act(addr: %s, err_count: %d, last_updated: %ld < %ld < %ld)",
-			exp_client_addr.c_str(), 1, pre_command_time, last_updated, post_command_time,
-			client_addr.c_str(), error_count, pre_command_time, last_updated, post_command_time
-		);
-	}
-
-	return EXIT_SUCCESS;
-}
-
-/**
- * @brief Flush the entries, and check that counting is performed properly for multiple cache entries.
- * @param cl CommandLine info for connection creation.
- * @param proxysql_admin An already oppened connection to ProxySQL Admin.
- *
- * @return 'EXIT_SUCCESS' in case of success, 'EXIT_FAILURE' otherwise.
- */
-int test_cache_entry_count_by_mult_invalid_conns(const CommandLine& cl, MYSQL* proxysql_admin) {
-	printf("\n");
-	diag("                 START TEST NUMBER 3                         ");
-	diag("-------------------------------------------------------------");
-
-	// Increase cache size
-	MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_cache_size=5");
-	MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_error_counts=5");
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-
-	// There shouldn't be any other entries in the cache for this test.
-	MYSQL_QUERY(proxysql_admin, "PROXYSQL FLUSH MYSQL CLIENT HOSTS");
-	int errors = 0;
-
-	uint64_t pre_command_time = monotonic_time();
-
-	printf("\n");
-	diag("Performing connections to fill 'client_host_cache'");
-	for (int i = 2; i < NUM_LOOPBACK_ADDRS; i++) {
-		std::string loopback_addr { "127.0.0." + std::to_string(i) };
-		for (errors = 0; errors < 2; errors++) {
-			int inv_user_errno = invalid_proxysql_conn(loopback_addr, cl);
-			diag("Client connection failed with error: %d", inv_user_errno);
-		}
-	}
-
-	diag("Performing checks over 'client_host_cache'");
-
-	std::vector<host_cache_entry> entries =
-		get_client_host_cache_entries(proxysql_admin);
-
-	ok(
-		entries.size() == NUM_LOOPBACK_ADDRS - 2,
-		"'client_host_cache' entries should be 'NUM_LOOPBACK_ADDRS' after issuing 'PROXYSQL FLUSH"
-		" MYSQL CLIENT HOSTS' and 'NUM_LOOPBACK_ADDRS' failed connections. Entries: '%ld'",
-		entries.size()
-	);
-
-	if (entries.size() == NUM_LOOPBACK_ADDRS - 2) {
-		uint32_t entry_num = 2;
-
-		for (const auto& entry : entries) {
-			const std::string client_addr { std::get<0>(entry) };
-			const uint32_t error_count { std::get<1>(entry) };
-			const uint64_t last_updated { std::get<2>(entry) };
-			uint64_t post_command_time = monotonic_time();
-
-			std::string exp_client_addr { "127.0.0." + std::to_string(entry_num) };
-
-			ok(
-				client_addr == exp_client_addr && error_count == errors &&
-				(pre_command_time < last_updated < post_command_time),
-				"Entry should match expected values - exp(addr: %s, err_count: %d, last_updated: %ld < %ld < %ld),"
-				" act(addr: %s, err_count: %d, last_updated: %ld < %ld < %ld)",
-				exp_client_addr.c_str(), errors, pre_command_time, last_updated, post_command_time,
-				client_addr.c_str(), error_count, pre_command_time, last_updated, post_command_time
-			);
-
-			entry_num += 1;
-		}
-	}
-
-	return EXIT_SUCCESS;
-}
-
-/**
- * @brief Flush the entries, and check:
- *    1. That counting is performed properly for multiple cache entries.
- *    2. Connections fail after the limit for one client.
- *    3. Clients are deleted after a succesfull connection is performed.
- * @param cl CommandLine info for connection creation.
- * @param proxysql_admin An already oppened connection to ProxySQL Admin.
- *
- * @return 'EXIT_SUCCESS' in case of success, 'EXIT_FAILURE' otherwise.
- */
-int test_client_exceeding_cache_error_limit(const CommandLine& cl, MYSQL* proxysql_admin) {
-	printf("\n");
-	diag("                 START TEST NUMBER 4                         ");
-	diag("-------------------------------------------------------------");
-
-	// Increase cache size
-	MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_cache_size=5");
-	MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_error_counts=5");
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-
-	// There shouldn't be any other entries in the cache for this test.
-	MYSQL_QUERY(proxysql_admin, "PROXYSQL FLUSH MYSQL CLIENT HOSTS");
-	int errors = 0;
-
-	std::vector<std::string> loopback_addrs {};
-	for (int i = 2; i < NUM_LOOPBACK_ADDRS; i++) {
-		loopback_addrs.push_back("127.0.0." + std::to_string(i));
-	}
-
-	uint64_t pre_command_time = monotonic_time();
-
-	printf("\n");
-	diag("Performing connections to fill 'client_host_cache'");
-	for (const auto loopback_addr : loopback_addrs) {
-		for (errors = 0; errors < 3; errors++) {
-			int inv_user_errno = invalid_proxysql_conn(loopback_addr, cl);
-			diag("Client connection failed with error: %d", inv_user_errno);
-		}
-	}
-
-	printf("\n");
-	diag("1. Check that counting is perfomred properly over multiple 'client_host_cache'");
-
-	std::vector<host_cache_entry> entries =
-		get_client_host_cache_entries(proxysql_admin);
-
-	ok(
-		entries.size() == NUM_LOOPBACK_ADDRS - 2,
-		"'client_host_cache' entries should be 'NUM_LOOPBACK_ADDRS' after issuing 'PROXYSQL FLUSH"
-		" MYSQL CLIENT HOSTS' and 'NUM_LOOPBACK_ADDRS' failed connections. Entries: '%ld'",
-		entries.size()
-	);
-
-	if (entries.size() == NUM_LOOPBACK_ADDRS - 2) {
-		uint32_t entry_num = 2;
-
-		for (const auto& entry : entries) {
-			const std::string client_addr { std::get<0>(entry) };
-			const uint32_t error_count { std::get<1>(entry) };
-			const uint64_t last_updated { std::get<2>(entry) };
-			uint64_t post_command_time = monotonic_time();
-
-			std::string exp_client_addr { "127.0.0." + std::to_string(entry_num) };
-
-			ok(
-				client_addr == exp_client_addr && error_count == errors &&
-				(pre_command_time < last_updated < post_command_time),
-				"Entry should match expected values - exp(addr: %s, err_count: %d, last_updated: %ld < %ld < %ld),"
-				" act(addr: %s, err_count: %d, last_updated: %ld < %ld < %ld)",
-				exp_client_addr.c_str(), errors, pre_command_time, last_updated, post_command_time,
-				client_addr.c_str(), error_count, pre_command_time, last_updated, post_command_time
-			);
-
-			entry_num += 1;
-		}
-	}
-
-	printf("\n");
-	diag("Performing connections to fill 'client_host_cache'");
-
-	const std::string loopback_addr { "127.0.0.4" };
-	uint32_t expected_errors = 5;
-
-	int limits = errors;
-
-	std::string command_res {};
-	int limit_conn_err = EXIT_SUCCESS;
-
-	for (int limits = errors; limits < 5 + 1; limits++) {
-		limit_conn_err = invalid_proxysql_conn(loopback_addr, cl, command_res);
-		diag("Client connection failed with error: (%d, %s)", limit_conn_err, command_res.c_str());
-	}
-	printf("\n");
-
-	diag("2. Checking the connection is denied when the limit is reached.");
-
-	ok(
-		limit_conn_err == 2013,
-		"Last connection should fail with 'ERROR 2013', it exceeded the error limit. ErrMsg: '%s'",
-		command_res.c_str()
-	);
-
-	std::vector<host_cache_entry> new_entries {
-		get_client_host_cache_entries(proxysql_admin)
-	};
-
-	auto cache_entry =
-		std::find_if(
-			std::begin(new_entries),
-			std::end(new_entries),
-			[&] (const host_cache_entry& elem) -> bool {
-				return std::get<0>(elem) == loopback_addr;
-			}
-		);
-
-	bool found_exp_values = false;
-	std::string client_address {};
-	uint32_t found_errors = 0;
-
-	if (cache_entry != std::end(new_entries)) {
-		client_address = std::get<0>(*cache_entry);
-		found_errors = std::get<1>(*cache_entry);
-
-		found_exp_values =
-			std::get<0>(*cache_entry) == loopback_addr &&
-			std::get<1>(*cache_entry) == expected_errors;
-	}
-
-	ok(
-		found_exp_values,
-		"Entry should match expected values - exp(addr: %s, err_count: %d), act(addr: %s, err_count: %d)",
-		loopback_addr.c_str(), expected_errors, client_address.c_str(), found_errors
-	);
-
-	diag("3. Check that clients are deleted from the cache when the connections are succesfully performed");
-
-	for (int i = 1; i < NUM_LOOPBACK_ADDRS; i++) {
-		// This client as exceeded the max failures
-
-		std::string loopback_addr { "127.0.0." + std::to_string(i) };
-
-		// Client has exceeded maximum connections failure is expected
-		if (i == 4) {
-			std::string conn_err_msg {};
-			int limit_conn_err = valid_proxysql_conn(loopback_addr, cl, conn_err_msg);
-
-			ok(
-				limit_conn_err == 2013,
-				"Connection should fail due to limit exceeded. ErrMsg: '%s'", conn_err_msg.c_str()
-			);
-		} else {
-			std::string command_res {};
-			int command_err = valid_proxysql_conn(loopback_addr, cl, command_res);
-			ok(
-				command_err == 0,
-				"Connection should succeed for clients which limit haven't been exceeded."
-			);
-		}
-	}
-
-	new_entries = get_client_host_cache_entries(proxysql_admin);
-	std::string last_client_addr { "" };
-	if (new_entries.size()) {
-		last_client_addr = std::get<0>(new_entries.back());
-	}
-
-	ok(
-		new_entries.size() == 1 && last_client_addr == "127.0.0.4",
-		"Only client address exceeding the limit should remain in the cache - exp('127.0.0.4'), act('%s')",
-		last_client_addr.c_str()
-	);
-	return EXIT_SUCCESS;
-}
-
-/**
- * @brief Flush the entries, fill the cache and check that the when the 'mysql-client_host_error_counts'
- *   is changed at runtime, connections are denied to a client exceeding the new limit.
- * @param cl CommandLine info for connection creation.
- * @param proxysql_admin An already oppened connection to ProxySQL Admin.
- *
- * @return 'EXIT_SUCCESS' in case of success, 'EXIT_FAILURE' otherwise.
- */
-int test_client_exceeding_changed_error_limit(const CommandLine& cl, MYSQL* proxysql_admin) {
-	printf("\n");
-	diag("                 START TEST NUMBER 5                         ");
-	diag("-------------------------------------------------------------");
-
-	// Increase cache size
-	printf("\n");
-	diag("Setting the value of 'mysql-client_host_cache_size' to '5'");
-
-	MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_cache_size=5");
-	MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_error_counts=5");
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-
-	// There shouldn't be any other entries in the cache for this test.
-	MYSQL_QUERY(proxysql_admin, "PROXYSQL FLUSH MYSQL CLIENT HOSTS");
-	int errors = 0;
-
-
-	uint64_t pre_command_time = monotonic_time();
-
-	std::string loopback_addr { "127.0.0.2" };
-	diag("Performing connections to fill 'client_host_cache'");
-
-	for (int i = 0; i < 4; i++) {
-		int inv_user_errno = invalid_proxysql_conn(loopback_addr, cl);
-		diag("Client connection failed with error: %d", inv_user_errno);
-	}
-
-	diag("Decreasing the value of 'mysql-client_host_error_counts' to '3'");
-	MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_error_counts=3");
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-
-	{
-		printf("\n");
-
-		std::string conn_err_msg {};
-		int valid_user_err = valid_proxysql_conn(loopback_addr, cl, conn_err_msg);
-		diag("Client connection failed with error: (%d, %s)", valid_user_err, conn_err_msg.c_str());
-
-		ok(
-			valid_user_err == 2013,
-			"Last connection should fail with 'ERROR 2013', it exceeded the error limit. ErrMsg: '%s'",
-			conn_err_msg.c_str()
-		);
-	}
-
-	return EXIT_SUCCESS;
-}
-
-/**
- * @brief Flush the entries, set 'mysql-client_host_cache_size' to '0', and check
- *   that cache isn't filled by connections timing out. Increase 'mysql-client_host_cache_size'
- *   and check that cache is filled by timeout connections.
- * @param cl CommandLine info for connection creation.
- * @param proxysql_admin An already oppened connection to ProxySQL Admin.
- *
- * @return 'EXIT_SUCCESS' in case of success, 'EXIT_FAILURE' otherwise.
- */
-int test_cache_size_decrease_by_new_connections(const CommandLine& cl, MYSQL* proxysql_admin) {
-	printf("\n");
-	diag("                 START TEST NUMBER 6                         ");
-	diag("-------------------------------------------------------------");
-
-	// Increase cache size
-	printf("\n");
-	diag("Setting the value of 'mysql-client_host_cache_size' to '5'");
-
-	MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_cache_size=5");
-	MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_error_counts=5");
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-
-	// There shouldn't be any other entries in the cache for this test.
-	MYSQL_QUERY(proxysql_admin, "PROXYSQL FLUSH MYSQL CLIENT HOSTS");
-	int errors = 0;
-
-	std::vector<std::string> loopback_addrs {};
-	for (int i = 2; i < NUM_LOOPBACK_ADDRS; i++) {
-		loopback_addrs.push_back("127.0.0." + std::to_string(i));
-	}
-
-	uint64_t pre_command_time = monotonic_time();
-
-	printf("\n");
-	diag("Performing connections to fill 'client_host_cache'");
-	for (const auto loopback_addr : loopback_addrs) {
-		for (errors = 0; errors < 3; errors++) {
-			int inv_user_errno = invalid_proxysql_conn(loopback_addr, cl);
-			diag("Client connection failed with error: %d", inv_user_errno);
-		}
-	}
-
-	diag("Decreasing the value of 'mysql-client_host_cache_size' to '3'");
-	MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_cache_size=1");
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-
-	// Update the latest entry in the cache, oldest member "10.200.1.2" should go away.
-	{
-		uint64_t pre_command_time = monotonic_time();
-
-		diag("1. Checking that the connection updates the entry and the oldest entry is removed");
-
-		std::string loopback_addr { "127.0.0.4" };
-
-		printf("\n");
-		int inv_user_err = invalid_proxysql_conn(loopback_addr, cl);
-		diag("Client connection failed with error: %d", inv_user_err);
-
-		std::vector<host_cache_entry> updated_entries {
-			get_client_host_cache_entries(proxysql_admin)
-		};
-
-		std::string exp_client_addr { "127.0.0.4" };
-
-		auto entry = std::find_if(
-			std::begin(updated_entries),
-			std::end(updated_entries),
-			[&] (const host_cache_entry& entry) -> bool {
-				return std::get<0>(entry) == exp_client_addr;
-			}
-		);
-
-		std::string act_client_addr {};
-		uint64_t last_updated = 0;
-
-		if (entry != std::end(updated_entries)) {
-			act_client_addr = std::get<0>(*entry);
-			last_updated = std::get<2>(*entry);
-		}
-
-		ok(
-			exp_client_addr == act_client_addr && last_updated > pre_command_time,
-			"Entry should be present and updated with the following values -"
-			" exp('%s', %ld > %ld), act('%s', %ld > %ld)", exp_client_addr.c_str(),
-			last_updated, pre_command_time, act_client_addr.c_str(), last_updated,
-			pre_command_time
-		);
-
-		// Oldest member shouldn't be present
-		std::string oldest_member { "127.0.0.2" };
-
-		auto oldest_entry = std::find_if(
-			std::begin(updated_entries),
-			std::end(updated_entries),
-			[&] (const host_cache_entry& entry) -> bool {
-				return std::get<0>(entry) == oldest_member;
-			}
-		);
-
-		ok(
-			oldest_entry == std::end(updated_entries),
-			"Oldest entry '%s' shouldn't be present in the cache.", oldest_member.c_str()
-		);
-
-		printf("\n");
-		diag("2. Checking that the same behavior is observed if connection comes from a non-cached address");
-
-		const std::string new_member { "127.0.0.5" };
-
-		inv_user_err = invalid_proxysql_conn(new_member, cl);
-		diag("Client connection failed with error: %d", inv_user_err);
-
-		diag("2.1 Checking that the address hasn't been added");
-
-		updated_entries = get_client_host_cache_entries(proxysql_admin);
-		auto new_entry = std::find_if(
-			std::begin(updated_entries), std::end(updated_entries),
-			[&] (const host_cache_entry& entry) -> bool {
-				return std::get<0>(entry) == new_member;
-			}
-		);
-
-		ok(
-			new_entry == std::end(updated_entries),
-			"New entry from address '127.0.0.5' shouldn't be present in the cache"
-		);
-
-		diag("2.1 Checking that the oldest address has been removed");
-		oldest_member = "127.0.0.3";
-
-		oldest_entry = std::find_if(
-			std::begin(updated_entries),
-			std::end(updated_entries),
-			[&] (const host_cache_entry& entry) -> bool {
-				return std::get<0>(entry) == oldest_member;
-			}
-		);
-
-		ok(
-			oldest_entry == std::end(updated_entries),
-			"Oldest entry '%s' shouldn't be present in the cache.", oldest_member.c_str()
-		);
-
-		diag("2.2 Checking that a successful connection gets a client removed");
-
-		const std::string forgotten_address { "127.0.0.4" };
-		std::string err_msg {};
-		int valid_conn_err = valid_proxysql_conn(forgotten_address, cl, err_msg);
-		if (valid_conn_err) {
-			diag("Failed to execute 'valid_proxysql_conn' at ('%s':'%d')", __FILE__, __LINE__);
-		}
-
-		updated_entries = get_client_host_cache_entries(proxysql_admin);
-		auto forgot_entry = std::find_if(
-			std::begin(updated_entries), std::end(updated_entries),
-			[&] (const host_cache_entry& entry) -> bool {
-				return std::get<0>(entry) == forgotten_address;
-			}
-		);
-
-		ok(
-			forgot_entry == std::end(updated_entries),
-			"Entry '%s' should have been forgotten due to successful connection.",
-			forgotten_address.c_str()
-		);
-	}
-
-	return EXIT_SUCCESS;
-}
-
-int create_tcp_conn(const CommandLine& cl, const std::string& addr) {
-	int sock = 0;
-	struct sockaddr_in serv_addr;
-
-	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
-		diag("_socket creation error");
-		return EXIT_FAILURE;
-	}
-
-	serv_addr.sin_family = AF_INET;
-	serv_addr.sin_port = htons(cl.port);
-
-	if(inet_pton(AF_INET, addr.c_str(), &serv_addr.sin_addr)<=0)  {
-		diag("Invalid address/ Address not supported");
-		return EXIT_FAILURE;
-	}
-
-	if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
-		diag("Connection Failed");
-		return EXIT_FAILURE;
-	}
-
-	return EXIT_SUCCESS;
-}
-
-/**
- * @brief Checks that client connections timeouts interact with the cache in the same way
- *   as regular client connection errors.
- * @param cl CommandLine info for connection creation.
- * @param proxysql_admin An already oppened connection to ProxySQL Admin.
- *
- * @return 'EXIT_SUCCESS' in case of success, 'EXIT_FAILURE' otherwise.
- */
-int test_cache_populated_timeout_conns(const CommandLine& cl, MYSQL* proxysql_admin) {
-	printf("\n");
-	diag("                 START TEST NUMBER 7                         ");
-	diag("-------------------------------------------------------------");
-
-	// Increase cache size
-	printf("\n");
-	diag("Setting the value of 'mysql-client_host_cache_size' to '0'");
-
-	// Disable the cache
-	MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_cache_size=0");
-	MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_error_counts=0");
-
-	// Decrease client connection timeout
-	const int client_timeout = 1000;
-	std::string set_connect_timeout_client { "SET mysql-connect_timeout_client=" + std::to_string(client_timeout) };
-
-	MYSQL_QUERY(proxysql_admin, set_connect_timeout_client.c_str());
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-
-	// There shouldn't be any other entries in the cache for the start of this test.
-	MYSQL_QUERY(proxysql_admin, "PROXYSQL FLUSH MYSQL CLIENT HOSTS");
-
-	int errors = 0;
-
-	// Create some connections timeout
-	printf("\n");
-	diag("Performing timeout connections to fill 'client_host_cache'");
-	std::vector<int> sockets {};
-	for (int i = 2; i < NUM_LOOPBACK_ADDRS; i++) {
-		std::string loopback_addr { "127.0.0." + std::to_string(i) };
-		int inv_user_errno = create_tcp_conn(cl, loopback_addr);
-		diag("Client connection failed with error: %d", inv_user_errno);
-	}
-	sleep((client_timeout / 1000) * 2 + 1);
-
-	std::vector<host_cache_entry> updated_entries = get_client_host_cache_entries(proxysql_admin);
-	ok(updated_entries.size() == 0, "Entries should be empty because cache was disabled.");
-
-	diag("Setting the value of 'mysql-client_host_cache_size' to '10'");
-	// Disable the cache
-	MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_cache_size=10");
-	MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_error_counts=10");
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-	MYSQL_QUERY(proxysql_admin, "PROXYSQL FLUSH MYSQL CLIENT HOSTS");
-
-	uint64_t pre_command_time = monotonic_time();
-
-	for (int i = 2; i < NUM_LOOPBACK_ADDRS; i++) {
-		std::string loopback_addr { "127.0.0." + std::to_string(i) };
-		for (errors = 0; errors < 2; errors++) {
-			int inv_user_errno = create_tcp_conn(cl, loopback_addr);
-			diag("Client connection timeout out with error: %d", inv_user_errno);
-		}
-	}
-	sleep((client_timeout / 1000) * 2 + 1);
-
-	updated_entries = get_client_host_cache_entries(proxysql_admin);
-	ok(updated_entries.size() == 3, "Cache should hold three entries for the timed out connections.");
-
-	int entry_num = 0;
-	for (const auto& entry : updated_entries) {
-		const std::string client_addr { std::get<0>(entry) };
-		const uint32_t error_count { std::get<1>(entry) };
-		const uint64_t last_updated { std::get<2>(entry) };
-		uint64_t post_command_time = monotonic_time();
-
-		std::string exp_client_addr { "127.0.0." + std::to_string(entry_num + 2) };
-
-		ok(
-			client_addr == exp_client_addr && error_count == errors &&
-			(pre_command_time < last_updated < post_command_time),
-			"Entry should match expected values - exp(addr: %s, err_count: %d, last_updated: %ld < %ld < %ld),"
-			" act(addr: %s, err_count: %d, last_updated: %ld < %ld < %ld)",
-			exp_client_addr.c_str(), errors, pre_command_time, last_updated, post_command_time,
-			client_addr.c_str(), error_count, pre_command_time, last_updated, post_command_time
-		);
-
-		entry_num += 1;
-	}
-
-
-	return EXIT_SUCCESS;
-}
-
-int main(int, char**) {
-	int res = 0;
-	CommandLine cl;
-
-	if (cl.getEnv()) {
-		diag("Failed to get the required environmental variables.");
-		return -1;
-	}
-
-	plan(30);
-
-	MYSQL* proxysql_admin = mysql_init(NULL);
-
-	// Initialize connections
-	if (!proxysql_admin) {
-		fprintf(
-			stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__,
-			mysql_error(proxysql_admin)
-		);
-		return -1;
-	}
-
-	// Connect to ProxySQL Admin
-	if (
-		!mysql_real_connect(
-			proxysql_admin, cl.host, cl.admin_username, cl.admin_password,
-			NULL, cl.admin_port, NULL, 0
-		)
-	) {
-		fprintf(
-			stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__,
-			mysql_error(proxysql_admin)
-		);
-		return -1;
-	}
-
-	// Setup the virtual namespaces to be used by the test
-	diag("                Setting up extra loopback addresses                  ");
-	diag("*********************************************************************");
-	printf("\n");
-
-	int setup_ns_i = 0;
-	const std::string t_create_loopback_addr { "sudo ip addr add 127.0.0.%d dev lo" };
-	const std::string t_delete_loopback_addr { "sudo ip addr delete 127.0.0.%d/32 dev lo" };
-
-	for (setup_ns_i = 2; setup_ns_i < NUM_LOOPBACK_ADDRS; setup_ns_i++) {
-		std::string create_loopback_addr {};
-		string_format(t_create_loopback_addr, create_loopback_addr, setup_ns_i);
-
-		int c_err = system(create_loopback_addr.c_str());
-		if (c_err) {
-			diag(
-				"Failed to create netns number '%d' with err: '%d'",
-				setup_ns_i, c_err
-			);
-			goto cleanup;
-		}
-	}
-
-	// Create two extra loopback addresses for testing 'connection_timeout'
-	for (; setup_ns_i < NUM_LOOPBACK_ADDRS + 2; setup_ns_i++) {
-		std::string create_ns_command {};
-		string_format(t_create_loopback_addr, create_ns_command, setup_ns_i);
-
-		int c_err = system(create_ns_command.c_str());
-		if (c_err) {
-			diag(
-				"Failed to create netns number '%d' with err: '%d'",
-				setup_ns_i, c_err
-			);
-			goto cleanup;
-		}
-	}
-
-	printf("\n");
-	diag("*********************************************************************");
-	printf("\n");
-
-	diag("                 Performing queries and checks                       ");
-	diag("*********************************************************************");
-	printf("\n");
-
-
-	test_cache_filled_by_invalid_conn(cl, proxysql_admin);
-	test_cache_entry_count_by_invalid_conn(cl, proxysql_admin);
-	test_cache_entry_count_by_mult_invalid_conns(cl, proxysql_admin);
-	test_client_exceeding_cache_error_limit(cl, proxysql_admin);
-	test_client_exceeding_changed_error_limit(cl, proxysql_admin);
-	test_cache_size_decrease_by_new_connections(cl, proxysql_admin);
-	test_cache_populated_timeout_conns(cl, proxysql_admin);
-
-cleanup:
-	// Cleanup the virtual namespaces to be used by the test
-	printf("\n");
-	diag("            Cleanup of testing network namespaces                    ");
-	diag("*********************************************************************");
-	printf("\n");
-
-	for (int i = 2; i < setup_ns_i; i++) {
-		std::string delete_loopback_addr {};
-		string_format(t_delete_loopback_addr, delete_loopback_addr, i);
-		system(delete_loopback_addr.c_str());
-	}
-
-	mysql_close(proxysql_admin);
-
-	return exit_status();
-}
diff --git a/test/tap/tests/test_client_limit_error.cpp b/test/tap/tests/test_client_limit_error.cpp
new file mode 100644
index 0000000000..ace8bdd76d
--- /dev/null
+++ b/test/tap/tests/test_client_limit_error.cpp
@@ -0,0 +1,776 @@
+/**
+ * @file test_client_limit_error.cpp
+ * @brief This test aims to verify the logic for the 'client_limit_error' feature.
+ *   NOTE: This test isn't executed automatically because it requires elevated privileges
+ *   for being able to run the scripts 'create_netns_n' and 'delete_netns_n' that creates
+ *   and delete the networks namespaces required for it.
+ *
+ * @details Right now the test verifies the following cases:
+ *  1. Enable the feature and checks that the error count is incremented when a single
+ *     client tries to connect and that the cache entry values match expected ones.
+ *  2. Flush the entries, and check that counting is performed properly for a
+ *     single cache entry.
+ *  3. Flush the entries, and check that counting is performed properly for
+ *     multiple cache entries.
+ *  4. Flush the entries, and check:
+ *       1. That counting is performed properly for multiple cache entries.
+ *       2. Connections fail after the limit for one client.
+ *       3. Clients are deleted after a succesfull connection is performed.
+ *  5. Flush the entries, fill the cache and check that when the
+ *  'mysql-client_host_error_counts' is changed at runtime, connections are denied
+ *  to a client exceeding the new limit.
+ *  6. Flush the entries, fill the cache and check that the when the
+ *  'mysql-client_host_cache_size' is changed at runtime:
+ *    1. The exceeding elements are cleaned with each new connection.
+ *    2. Check that is not relevant if the element was or not present 
+ *       in the cache.
+ *    3. Checks that a proper connection is performed succesfully and the element is
+ *    removed from the cache
+ *
+ * @date 2021-09-10
+ */
+
+#include <unistd.h>
+#include <signal.h>
+#include <pthread.h>
+#include <stdio.h>
+
+#include <atomic>
+#include <algorithm>
+#include <tuple>
+#include <vector>
+#include <string>
+#include <thread>
+#include <iostream>
+#include <fstream>
+
+#include <libconfig.h>
+#include <proxysql_utils.h>
+#include <mysql.h>
+
+#include "tap.h"
+#include "command_line.h"
+#include "utils.h"
+
+const uint32_t NUM_NETWORK_NAMESPACES = 5;
+
+using host_cache_entry = std::tuple<std::string, uint32_t, uint64_t>;
+
+inline unsigned long long monotonic_time() {
+  struct timespec ts;
+  clock_gettime(CLOCK_MONOTONIC, &ts);
+  return (((unsigned long long) ts.tv_sec) * 1000000) + (ts.tv_nsec / 1000);
+}
+
+std::vector<host_cache_entry> get_client_host_cache_entries(MYSQL* proxysql_admin) {
+	int rc = mysql_query(
+		proxysql_admin,
+		"SELECT * FROM stats.stats_mysql_client_host_cache ORDER BY client_address"
+	);
+
+	MYSQL_ROW row = NULL;
+	MYSQL_RES* proxy_res = mysql_store_result(proxysql_admin);
+	std::vector<host_cache_entry> host_cache_entries {};
+
+	while ((row = mysql_fetch_row(proxy_res))) {
+		std::string client_address = row[0];
+		uint32_t error_count = atoi(row[1]);
+		uint64_t last_update = atoll(row[2]);
+
+		host_cache_entries.push_back({client_address, error_count, last_update});
+	}
+
+	mysql_free_result(proxy_res);
+
+	return host_cache_entries;
+}
+
+int main(int, char**) {
+	int res = 0;
+	CommandLine cl;
+
+	if (cl.getEnv()) {
+		diag("Failed to get the required environmental variables.");
+		return -1;
+	}
+
+	plan(27);
+
+	MYSQL* proxysql_admin = mysql_init(NULL);
+
+	// Initialize connections
+	if (!proxysql_admin) {
+		fprintf(
+			stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__,
+			mysql_error(proxysql_admin)
+		);
+		return -1;
+	}
+
+	// Connect to ProxySQL Admin
+	if (
+		!mysql_real_connect(
+			proxysql_admin, cl.host, cl.admin_username, cl.admin_password,
+			NULL, cl.admin_port, NULL, 0
+		)
+	) {
+		fprintf(
+			stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__,
+			mysql_error(proxysql_admin)
+		);
+		return -1;
+	}
+
+	// Setup the virtual namespaces to be used by the test
+	diag("                Setting up testing network namespaces                ");
+	diag("*********************************************************************");
+	printf("\n");
+
+	int setup_ns_i = 0;
+	const std::string t_create_ns_command =
+		std::string { cl.workdir } + "/client_host_err/create_netns_n.sh %d";
+	for (setup_ns_i = 1; setup_ns_i < NUM_NETWORK_NAMESPACES; setup_ns_i++) {
+		std::string create_ns_command {};
+		string_format(t_create_ns_command, create_ns_command, setup_ns_i);
+
+		int c_err = system(create_ns_command.c_str());
+		if (c_err) {
+			diag(
+				"Failed to create netns number '%d' with err: '%d'",
+				setup_ns_i, c_err
+			);
+			goto cleanup;
+		}
+	}
+
+	printf("\n");
+	diag("*********************************************************************");
+	printf("\n");
+
+	diag("                 Performing queries and checks                       ");
+	diag("*********************************************************************");
+	printf("\n");
+
+	{
+		const std::string t_inv_user_command =
+			"ip netns exec ns%d mysql -h10.200.%d.1 -uinv_user -pinv_pass -P6033";
+		const std::string t_valid_connection_command {
+			"ip netns exec ns%d mysql -h10.200.%d.1 -uroot -proot -P6033 -e'DO 1' 2>&1"
+		};
+
+		// 1. Enable the feature check that error count is incremented when a
+		// new client fails to connect, and that the cache entry values are the
+		// expected ones.
+		{
+			printf("\n");
+			diag("                 START TEST NUMBER 1                         ");
+			diag("-------------------------------------------------------------");
+
+			MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_cache_size=1");
+			MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_error_counts=5");
+			MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
+
+			// There shouldn't be any other entries in the cache for this test.
+			MYSQL_QUERY(proxysql_admin, "PROXYSQL FLUSH MYSQL CLIENT HOSTS");
+
+			std::string inv_user_command {};
+			string_format(t_inv_user_command, inv_user_command, 1, 1);
+			uint64_t pre_command_time = monotonic_time();
+
+			diag("Performing connections to fill 'client_host_cache'");
+
+			printf("\n");
+			int inv_user_errno = system(inv_user_command.c_str());
+			diag("Client connection failed with error: %d", inv_user_errno);
+			printf("\n");
+
+			diag("Performing checks over 'client_host_cache'");
+
+			std::vector<host_cache_entry> entries =
+				get_client_host_cache_entries(proxysql_admin);
+
+			ok(
+				entries.size() == 1,
+				"'client_host_cache' entries should be '1' after issuing 'PROXYSQL FLUSH"
+				" MYSQL CLIENT HOSTS' and one failed connection."
+			);
+
+			if (entries.size() == 1) {
+				host_cache_entry unique_entry { entries.back() };
+				const std::string client_addr { std::get<0>(unique_entry) };
+				const uint32_t error_count { std::get<1>(unique_entry) };
+				const uint64_t last_updated { std::get<2>(unique_entry) };
+				uint64_t post_command_time = monotonic_time();
+
+				ok(
+					client_addr == "10.200.1.2" && error_count == 1 &&
+					(pre_command_time < last_updated < post_command_time),
+					"Entry should match expected values - exp(addr: %s, err_count: %d, last_updated: %ld < %ld < %ld),"
+					" act(addr: %s, err_count: %d, last_updated: %ld < %ld < %ld)",
+					"10.200.1.2", 1, pre_command_time, last_updated, post_command_time,
+					client_addr.c_str(), error_count, pre_command_time, last_updated, post_command_time
+				);
+			}
+		}
+
+		// 2. Flush the entries, and check that counting is performed properly for a
+		// single cache entry.
+		{
+			printf("\n");
+			diag("                 START TEST NUMBER 2                         ");
+			diag("-------------------------------------------------------------");
+
+
+			// There shouldn't be any other entries in the cache for this test.
+			MYSQL_QUERY(proxysql_admin, "PROXYSQL FLUSH MYSQL CLIENT HOSTS");
+			int errors = 0;
+
+			std::string inv_user_command {};
+			string_format(t_inv_user_command, inv_user_command, 1, 1);
+			uint64_t pre_command_time = monotonic_time();
+
+			printf("\n");
+			diag("Performing connections to fill 'client_host_cache'");
+			for (errors = 0; errors < 5; errors++) {
+				printf("\n");
+				int inv_user_errno = system(inv_user_command.c_str());
+				diag("Client connection failed with error: %d", inv_user_errno);
+			}
+			printf("\n");
+
+			diag("Performing checks over 'client_host_cache'");
+
+			std::vector<host_cache_entry> entries =
+				get_client_host_cache_entries(proxysql_admin);
+
+			ok(
+				entries.size() == 1,
+				"'client_host_cache' entries should be '1' after issuing 'PROXYSQL FLUSH"
+				" MYSQL CLIENT HOSTS' and one failed connection."
+			);
+
+			if (entries.size() == 1) {
+				host_cache_entry unique_entry { entries.back() };
+				const std::string client_addr { std::get<0>(unique_entry) };
+				const uint32_t error_count { std::get<1>(unique_entry) };
+				const uint64_t last_updated { std::get<2>(unique_entry) };
+				uint64_t post_command_time = monotonic_time();
+
+				ok(
+					client_addr == "10.200.1.2" && error_count == errors &&
+					(pre_command_time < last_updated < post_command_time),
+					"Entry should match expected values - exp(addr: %s, err_count: %d, last_updated: %ld < %ld < %ld),"
+					" act(addr: %s, err_count: %d, last_updated: %ld < %ld < %ld)",
+					"10.200.1.2", 1, pre_command_time, last_updated, post_command_time,
+					client_addr.c_str(), error_count, pre_command_time, last_updated, post_command_time
+				);
+			}
+		}
+
+		// 3. Flush the entries, and check that counting is performed properly for
+		// multiple cache entries.
+		{
+			printf("\n");
+			diag("                 START TEST NUMBER 3                         ");
+			diag("-------------------------------------------------------------");
+
+			// Increase cache size
+			MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_cache_size=5");
+			MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_error_counts=5");
+			MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
+
+			// There shouldn't be any other entries in the cache for this test.
+			MYSQL_QUERY(proxysql_admin, "PROXYSQL FLUSH MYSQL CLIENT HOSTS");
+			int errors = 0;
+
+			// Prepare several commands from different network namespaces
+			std::vector<std::string> inv_connection_commands {};
+			for (int i = 1; i < NUM_NETWORK_NAMESPACES; i++) {
+				std::string inv_user_command {};
+				string_format(t_inv_user_command, inv_user_command, i, i);
+				inv_connection_commands.push_back(inv_user_command);
+			}
+
+			uint64_t pre_command_time = monotonic_time();
+
+			printf("\n");
+			diag("Performing connections to fill 'client_host_cache'");
+			for (const auto inv_conn_command : inv_connection_commands) {
+				for (errors = 0; errors < 2; errors++) {
+					printf("\n");
+					int inv_user_errno = system(inv_conn_command.c_str());
+					diag("Client connection failed with error: %d", inv_user_errno);
+				}
+				printf("\n");
+			}
+
+			diag("Performing checks over 'client_host_cache'");
+
+			std::vector<host_cache_entry> entries =
+				get_client_host_cache_entries(proxysql_admin);
+
+			ok(
+				entries.size() == NUM_NETWORK_NAMESPACES - 1,
+				"'client_host_cache' entries should be 'NUM_NETWORK_NAMESPACES' after issuing 'PROXYSQL FLUSH"
+				" MYSQL CLIENT HOSTS' and 'NUM_NETWORK_NAMESPACES' failed connections. Entries: '%ld'",
+				entries.size()
+			);
+
+			if (entries.size() == NUM_NETWORK_NAMESPACES - 1) {
+				uint32_t entry_num = 1;
+
+				for (const auto& entry : entries) {
+					const std::string client_addr { std::get<0>(entry) };
+					const uint32_t error_count { std::get<1>(entry) };
+					const uint64_t last_updated { std::get<2>(entry) };
+					uint64_t post_command_time = monotonic_time();
+
+					std::string t_exp_client_addr { "10.200.%d.2" };
+					std::string exp_client_addr {};
+					string_format(t_exp_client_addr, exp_client_addr, entry_num);
+
+					ok(
+						client_addr == exp_client_addr && error_count == errors &&
+						(pre_command_time < last_updated < post_command_time),
+						"Entry should match expected values - exp(addr: %s, err_count: %d, last_updated: %ld < %ld < %ld),"
+						" act(addr: %s, err_count: %d, last_updated: %ld < %ld < %ld)",
+						exp_client_addr.c_str(), errors, pre_command_time, last_updated, post_command_time,
+						client_addr.c_str(), error_count, pre_command_time, last_updated, post_command_time
+					);
+
+					entry_num += 1;
+				}
+			}
+		}
+
+		// 4. Flush the entries, and check:
+		//   1. That counting is performed properly for multiple cache entries.
+		//   2. Connections fail after the limit for one client.
+		//   3. Clients are deleted after a succesfull connection is performed.
+		{
+			printf("\n");
+			diag("                 START TEST NUMBER 4                         ");
+			diag("-------------------------------------------------------------");
+
+			// Increase cache size
+			MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_cache_size=5");
+			MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_error_counts=5");
+			MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
+
+			// There shouldn't be any other entries in the cache for this test.
+			MYSQL_QUERY(proxysql_admin, "PROXYSQL FLUSH MYSQL CLIENT HOSTS");
+			int errors = 0;
+
+			// Prepare several commands from different network namespaces
+			std::vector<std::string> inv_connection_commands {};
+			for (int i = 1; i < NUM_NETWORK_NAMESPACES; i++) {
+				std::string inv_user_command {};
+				string_format(t_inv_user_command, inv_user_command, i, i);
+				inv_connection_commands.push_back(inv_user_command);
+			}
+
+			uint64_t pre_command_time = monotonic_time();
+
+			printf("\n");
+			diag("Performing connections to fill 'client_host_cache'");
+			for (const auto inv_conn_command : inv_connection_commands) {
+				for (errors = 0; errors < 3; errors++) {
+					printf("\n");
+					int inv_user_errno = system(inv_conn_command.c_str());
+					diag("Client connection failed with error: %d", inv_user_errno);
+				}
+				printf("\n");
+			}
+
+			printf("\n");
+			diag("1. Check that counting is perfomred properly over multiple 'client_host_cache'");
+
+			std::vector<host_cache_entry> entries =
+				get_client_host_cache_entries(proxysql_admin);
+
+			ok(
+				entries.size() == NUM_NETWORK_NAMESPACES - 1,
+				"'client_host_cache' entries should be 'NUM_NETWORK_NAMESPACES' after issuing 'PROXYSQL FLUSH"
+				" MYSQL CLIENT HOSTS' and 'NUM_NETWORK_NAMESPACES' failed connections. Entries: '%ld'",
+				entries.size()
+			);
+
+			if (entries.size() == NUM_NETWORK_NAMESPACES - 1) {
+				uint32_t entry_num = 1;
+
+				for (const auto& entry : entries) {
+					const std::string client_addr { std::get<0>(entry) };
+					const uint32_t error_count { std::get<1>(entry) };
+					const uint64_t last_updated { std::get<2>(entry) };
+					uint64_t post_command_time = monotonic_time();
+
+					std::string t_exp_client_addr { "10.200.%d.2" };
+					std::string exp_client_addr {};
+					string_format(t_exp_client_addr, exp_client_addr, entry_num);
+
+					ok(
+						client_addr == exp_client_addr && error_count == errors &&
+						(pre_command_time < last_updated < post_command_time),
+						"Entry should match expected values - exp(addr: %s, err_count: %d, last_updated: %ld < %ld < %ld),"
+						" act(addr: %s, err_count: %d, last_updated: %ld < %ld < %ld)",
+						exp_client_addr.c_str(), errors, pre_command_time, last_updated, post_command_time,
+						client_addr.c_str(), error_count, pre_command_time, last_updated, post_command_time
+					);
+
+					entry_num += 1;
+				}
+			}
+
+			printf("\n");
+			diag("Performing connections to fill 'client_host_cache'");
+
+			uint32_t expected_ns = 4;
+			const std::string expected_address { "10.200.4.2" };
+			uint32_t expected_errors = 5;
+
+			int limits = errors;
+			std::string inv_user_command_limit {};
+			const std::string t_stderr_inv_user_command {
+				"ip netns exec ns%d mysql -h10.200.%d.1 -uinv_user -pinv_pass -P6033 2>&1"
+			};
+			string_format(t_stderr_inv_user_command, inv_user_command_limit, 4, 4);
+
+			std::string command_res {};
+			for (int limits = errors; limits < 5 + 1; limits++) {
+				printf("\n");
+				int inv_user_limit_err = exec(inv_user_command_limit.c_str(), command_res);
+				diag("Client connection failed with error: (%d, %s)", inv_user_limit_err, command_res.c_str());
+			}
+			printf("\n");
+
+			diag("2. Checking the connection is denied when the limit is reached.");
+
+			auto limit_error = command_res.find("ERROR 2013 (HY000)");
+			ok(
+				limit_error != std::string::npos,
+				"Last connection should fail with 'ERROR 2013', it exceeded the error limit. ErrMsg: '%s'",
+				command_res.c_str()
+			);
+
+			std::vector<host_cache_entry> new_entries {
+				get_client_host_cache_entries(proxysql_admin)
+			};
+
+			auto cache_entry =
+				std::find_if(
+					std::begin(new_entries),
+					std::end(new_entries),
+					[&] (const host_cache_entry& elem) -> bool {
+						return std::get<0>(elem) == expected_address;
+					}
+				);
+
+			bool found_exp_values = false;
+			std::string client_address {};
+			uint32_t found_errors = 0;
+
+			if (cache_entry != std::end(new_entries)) {
+				client_address = std::get<0>(*cache_entry);
+				found_errors = std::get<1>(*cache_entry);
+
+				found_exp_values =
+					std::get<0>(*cache_entry) == expected_address &&
+					std::get<1>(*cache_entry) == expected_errors;
+			}
+
+			ok(
+				found_exp_values,
+				"Entry should match expected values - exp(addr: %s, err_count: %d), act(addr: %s, err_count: %d)",
+				expected_address.c_str(), expected_errors, client_address.c_str(), found_errors
+			);
+
+			diag("3. Check that clients are deleted from the cache when the connections are succesfully performed");
+
+			for (int i = 1; i < NUM_NETWORK_NAMESPACES; i++) {
+				// This client as exceeded the max failures
+
+				std::string valid_connection_command {};
+				string_format(t_valid_connection_command, valid_connection_command, i, i);
+
+				// Client has exceeded maximum connections failure is expected
+				if (i == 4) {
+					std::string command_res {};
+					exec(valid_connection_command, command_res);
+					auto limit_error = command_res.find("ERROR 2013 (HY000)");
+
+					ok(
+						limit_error != std::string::npos,
+						"Connection should fail due to limit exceeded. ErrMsg: '%s'", command_res.c_str()
+					);
+				} else {
+					int command_err = system(valid_connection_command.c_str());
+					ok(
+						command_err == 0,
+						"Connection should succeed for clients which limit haven't been exceeded."
+					);
+				}
+			}
+
+			new_entries = get_client_host_cache_entries(proxysql_admin);
+			ok(
+				new_entries.size() == 1 &&
+				std::get<0>(new_entries.back()) == "10.200.4.2",
+				"Only client address exceeding the limit should remain in the cache -"
+				" exp('10.200.4.2'), act('%s')", std::get<0>(new_entries.back()).c_str()
+			);
+		}
+
+		// 5. Flush the entries, fill the cache and check that the when the
+		// 'mysql-client_host_error_counts' is changed at runtime, connections are denied
+		// to a client exceeding the new limit.
+		{
+			printf("\n");
+			diag("                 START TEST NUMBER 5                         ");
+			diag("-------------------------------------------------------------");
+
+			// Increase cache size
+			printf("\n");
+			diag("Setting the value of 'mysql-client_host_cache_size' to '5'");
+
+			MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_cache_size=5");
+			MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_error_counts=5");
+			MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
+
+			// There shouldn't be any other entries in the cache for this test.
+			MYSQL_QUERY(proxysql_admin, "PROXYSQL FLUSH MYSQL CLIENT HOSTS");
+			int errors = 0;
+
+			std::string inv_user_command {};
+			string_format(t_inv_user_command, inv_user_command, 1, 1);
+			uint64_t pre_command_time = monotonic_time();
+
+			diag("Performing connections to fill 'client_host_cache'");
+
+			for (int i = 0; i < 4; i++) {
+				printf("\n");
+				int inv_user_errno = system(inv_user_command.c_str());
+				diag("Client connection failed with error: %d", inv_user_errno);
+				printf("\n");
+			}
+
+			diag("Decreasing the value of 'mysql-client_host_error_counts' to '3'");
+			MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_error_counts=3");
+			MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
+
+			{
+				printf("\n");
+				std::string valid_user_command {};
+				string_format(t_valid_connection_command, valid_user_command, 1, 1);
+
+				std::string command_res {};
+				int valid_user_err = exec(valid_user_command.c_str(), command_res);
+				diag("Client connection failed with error: (%d, %s)", valid_user_err, command_res.c_str());
+
+				auto limit_error = command_res.find("ERROR 2013 (HY000)");
+				ok(
+					limit_error != std::string::npos,
+					"Last connection should fail with 'ERROR 2013', it exceeded the error limit. ErrMsg: '%s'",
+					command_res.c_str()
+				);
+			}
+		}
+
+		// 6. Flush the entries, fill the cache and check that the when the
+		// 'mysql-client_host_cache_size' is changed at runtime, the exceeding
+		// elements are cleaned with each new connection. Without being relevant if was
+		// present or not in the cache.
+		{
+			printf("\n");
+			diag("                 START TEST NUMBER 6                         ");
+			diag("-------------------------------------------------------------");
+
+			// Increase cache size
+			printf("\n");
+			diag("Setting the value of 'mysql-client_host_cache_size' to '5'");
+
+			MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_cache_size=5");
+			MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_error_counts=5");
+			MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
+
+			// There shouldn't be any other entries in the cache for this test.
+			MYSQL_QUERY(proxysql_admin, "PROXYSQL FLUSH MYSQL CLIENT HOSTS");
+			int errors = 0;
+
+			// Fill the cache with the entries from all the created namespaces
+			{
+				std::vector<std::string> inv_connection_commands {};
+				for (int i = 1; i < NUM_NETWORK_NAMESPACES; i++) {
+					std::string inv_user_command {};
+					string_format(t_inv_user_command, inv_user_command, i, i);
+					inv_connection_commands.push_back(inv_user_command);
+				}
+
+				printf("\n");
+				diag("Performing connections to fill 'client_host_cache'");
+				for (const auto inv_conn_command : inv_connection_commands) {
+					for (errors = 0; errors < 3; errors++) {
+						printf("\n");
+						int inv_user_errno = system(inv_conn_command.c_str());
+						diag("Client connection failed with error: %d", inv_user_errno);
+					}
+					printf("\n");
+				}
+				printf("\n");
+			}
+
+			diag("Decreasing the value of 'mysql-client_host_cache_size' to '3'");
+			MYSQL_QUERY(proxysql_admin, "SET mysql-client_host_cache_size=1");
+			MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
+
+			// Update the latest entry in the cache, oldest member "10.200.1.2" should go away.
+			{
+				uint64_t pre_command_time = monotonic_time();
+
+				diag("1. Checking that the connection updates the entry and the oldest entry is removed");
+
+				std::string inv_user_command {};
+				string_format(t_inv_user_command, inv_user_command, 4, 4);
+
+				printf("\n");
+				int inv_user_err = system(inv_user_command.c_str());
+				diag("Client connection failed with error: %d", inv_user_err);
+				printf("\n");
+
+				std::vector<host_cache_entry> updated_entries {
+					get_client_host_cache_entries(proxysql_admin)
+				};
+
+				std::string exp_client_addr { "10.200.4.2" };
+
+				auto entry = std::find_if(
+					std::begin(updated_entries),
+					std::end(updated_entries),
+					[&] (const host_cache_entry& entry) -> bool {
+						return std::get<0>(entry) == exp_client_addr;
+					}
+				);
+
+				std::string act_client_addr {};
+				uint64_t last_updated = 0;
+
+				if (entry != std::end(updated_entries)) {
+					act_client_addr = std::get<0>(*entry);
+					last_updated = std::get<2>(*entry);
+				}
+
+				ok(
+					exp_client_addr == act_client_addr && last_updated > pre_command_time,
+					"Entry should be present and updated with the following values -"
+					" exp('%s', %ld > %ld), act('%s', %ld > %ld)", exp_client_addr.c_str(),
+					last_updated, pre_command_time, act_client_addr.c_str(), last_updated,
+					pre_command_time
+				);
+
+				// Oldest member shouldn't be present
+				std::string oldest_member { "10.200.1.2" };
+
+				auto oldest_entry = std::find_if(
+					std::begin(updated_entries),
+					std::end(updated_entries),
+					[&] (const host_cache_entry& entry) -> bool {
+						return std::get<0>(entry) == oldest_member;
+					}
+				);
+
+				ok(
+					oldest_entry == std::end(updated_entries),
+					"Oldest entry '%s' shouldn't be present in the cache.", oldest_member.c_str()
+				);
+
+				printf("\n");
+				diag("2. Checking that the same behavior is observed if connection comes from a non-cached address");
+
+				string_format(t_inv_user_command, inv_user_command, 1, 1);
+
+				printf("\n");
+				inv_user_err = system(inv_user_command.c_str());
+				diag("Client connection failed with error: %d", inv_user_err);
+				printf("\n");
+
+				diag("2.1 Checking that the address hasn't been added");
+
+				const std::string new_member { "10.200.1.2" };
+
+				updated_entries = get_client_host_cache_entries(proxysql_admin);
+				auto new_entry = std::find_if(
+					std::begin(updated_entries),
+					std::end(updated_entries),
+					[&] (const host_cache_entry& entry) -> bool {
+						return std::get<0>(entry) == new_member;
+					}
+				);
+
+				ok(
+					new_entry == std::end(updated_entries),
+					"New entry from address '10.200.1.2' shouldn't be present in the cache"
+				);
+
+				printf("\n");
+				diag("2.1 Checking that the oldest address has been removed");
+				oldest_member = "10.200.2.2";
+
+				oldest_entry = std::find_if(
+					std::begin(updated_entries),
+					std::end(updated_entries),
+					[&] (const host_cache_entry& entry) -> bool {
+						return std::get<0>(entry) == oldest_member;
+					}
+				);
+
+				ok(
+					oldest_entry == std::end(updated_entries),
+					"Oldest entry '%s' shouldn't be present in the cache.", oldest_member.c_str()
+				);
+
+				printf("\n");
+				diag("2.2 Checking that a successful connection gets a client removed");
+				printf("\n");
+
+				std::string valid_connection_command {};
+				string_format(t_valid_connection_command, valid_connection_command, 3, 3);
+				system(valid_connection_command.c_str());
+
+				const std::string forgotten_address { "10.200.3.2" };
+
+				updated_entries = get_client_host_cache_entries(proxysql_admin);
+				auto forgot_entry = std::find_if(
+					std::begin(updated_entries),
+					std::end(updated_entries),
+					[&] (const host_cache_entry& entry) -> bool {
+						return std::get<0>(entry) == forgotten_address;
+					}
+				);
+
+				ok(
+					forgot_entry == std::end(updated_entries),
+					"Entry '%s' should have been forgotten due to successful connection.",
+					forgotten_address.c_str()
+				);
+			}
+		}
+	}
+
+cleanup:
+	// Cleanup the virtual namespaces to be used by the test
+	printf("\n");
+	diag("            Cleanup of testing network namespaces                    ");
+	diag("*********************************************************************");
+	printf("\n");
+
+	const std::string t_delete_ns_command =
+		std::string { cl.workdir } + "/client_host_err/delete_netns_n.sh %d";
+	for (int i = 1; i < setup_ns_i; i++) {
+		std::string delete_ns_command {};
+		string_format(t_delete_ns_command, delete_ns_command, i);
+		system(delete_ns_command.c_str());
+	}
+
+	mysql_close(proxysql_admin);
+
+	return exit_status();
+}
diff --git a/test/tap/tests/test_cluster_sync-t.cpp b/test/tap/tests/test_cluster_sync-t.cpp
index f121500820..cf1f7bcd2a 100644
--- a/test/tap/tests/test_cluster_sync-t.cpp
+++ b/test/tap/tests/test_cluster_sync-t.cpp
@@ -168,9 +168,8 @@ int main(int, char**) {
 		const std::string stats_db = std::string(cl.workdir) + "test_cluster_sync_config/proxysql_stats.db";
 
 		const std::string docker_command =
-			std::string("docker run -p 16032:6032 -e ASAN_OPTIONS=abort_on_error=0:halt_on_error=0:fast_unwind_on_fatal=1:detect_leaks=0 ") +
-			"-v " + std::string(cl.workdir) + "../../../:/tmp/proxysql ubuntu:20.04 sh -c" +
-			" \"./tmp/proxysql/src/proxysql -f -M -c /tmp/proxysql/test/tap/tests/test_cluster_sync_config/test_cluster_sync.cnf\" " +
+			std::string("docker run -p 16032:6032 ") + "-v " + std::string(cl.workdir) + "../../../:/tmp/proxysql"
+			" ubuntu:19.10 sh -c \"./tmp/proxysql/src/proxysql -f -M -c /tmp/proxysql/test/tap/tests/test_cluster_sync_config/test_cluster_sync.cnf\" " +
 			std::string("> ") + cluster_sync_node_stderr + " 2>&1";
 
 		int exec_res = system(docker_command.c_str());
@@ -1268,13 +1267,11 @@ int main(int, char**) {
 	mysql_options(proxysql_replica, MYSQL_OPT_WRITE_TIMEOUT, &mysql_timeout);
 	mysql_query(proxysql_replica, "PROXYSQL SHUTDOWN");
 	proxy_replica_th.join();
-	mysql_close(proxysql_replica);
 
 	remove(fmt_config_file.c_str());
 
 	MYSQL_QUERY(proxysql_admin, "DELETE FROM proxysql_servers");
 	MYSQL_QUERY(proxysql_admin, "LOAD PROXYSQL SERVERS TO RUNTIME");
-	mysql_close(proxysql_admin);
 
 	return exit_status();
 }
diff --git a/test/tap/tests/test_com_reset_connection_com_change_user-t.cpp b/test/tap/tests/test_com_reset_connection_com_change_user-t.cpp
new file mode 100644
index 0000000000..ee64d56abd
--- /dev/null
+++ b/test/tap/tests/test_com_reset_connection_com_change_user-t.cpp
@@ -0,0 +1,1211 @@
+/**
+ * @file test_com_reset_connection_com_change_user-t.cpp
+ * @brief This test checks session cleanup for 'COM_RESET_CONNECTION' and 'COM_CHANGE_USER'.
+ * @details The test is going to verify that both 'COM_RESET_CONNECTION' and 'COM_CHANGE_USER':
+ *   - Rollbacks active transactions.
+ *   - Closes active prepared statements
+ *   - Clears user variables.
+ *   - Variables tracked by ProxySQL are reset.
+ *   - Sessions others than 'PROXYSQL_SESSION_MYSQL' and 'PROXYSQL_SESSION_SQLITE' report '1047'
+ *     error when 'COM_RESET_CONNECTION' is received.
+ *   - Relevant session variables are recovered.
+ */
+
+#include <cstring>
+#include <vector>
+#include <string>
+#include <stdio.h>
+#include <tuple>
+#include <iostream>
+#include <unistd.h>
+
+#include <mysql.h>
+#include <mysql/mysqld_error.h>
+
+#include "command_line.h"
+#include "proxysql_utils.h"
+#include "json.hpp"
+#include "tap.h"
+#include "utils.h"
+
+using nlohmann::json;
+using var_val = std::pair<std::string, std::string>;
+
+const std::vector<std::string> tracked_variables {
+	"sql_log_bin", "sql_mode", "time_zone", "sql_auto_is_null",  "sql_safe_updates", "session_track_gtids",
+	"max_join_size", "net_write_timeout", "sql_select_limit",  "sql_select_limit", "character_set_results",
+	"transaction_isolation", "transaction_read_only", "sql_auto_is_null", "collation_connection",
+	"character_set_connection", "character_set_client", /*"character_set_database",*/ "group_concat_max_len",
+	"wsrep_sync_wait"
+};
+
+void variable_rows_to_json(MYSQL_RES *result, json& j) {
+	if(!result) return;
+	MYSQL_ROW row;
+
+	while ((row = mysql_fetch_row(result))) {
+		j[row[0]] = row[1];
+	}
+}
+
+int get_tracked_mysql_vars(MYSQL* proxysql, std::vector<var_val>& vars) {
+	int err = 0;
+	std::string query {
+		"SELECT /*+ ;hostgroup=0 */ LOWER(variable_name), variable_value FROM performance_schema.session_variables WHERE variable_name IN ("
+	};
+
+	for (const auto& varname : tracked_variables) {
+		query += "'" + varname + "'";
+
+		if (&varname != &tracked_variables.back()) {
+			query += ",";
+		}
+	}
+
+	query += ")";
+	err = mysql_query(proxysql, query.c_str());
+	if (err != EXIT_SUCCESS) {
+		return mysql_errno(proxysql);
+	}
+
+	MYSQL_RES* result = mysql_store_result(proxysql);
+	// Extract all rows into variables
+	{
+		MYSQL_ROW row = NULL;
+
+		while ((row = mysql_fetch_row(result))) {
+			var_val var_value {
+				row[0] == NULL ? "NULL" : row[0],
+				row[1] == NULL ? "NULL" : row[1]
+			};
+			vars.push_back(var_value);
+		}
+	}
+	mysql_free_result(result);
+
+	return EXIT_SUCCESS;
+}
+
+using track_variable_spec = std::tuple<std::string, std::string, std::string, std::string>;
+
+std::vector<track_variable_spec> tracked_vars {
+//  TODO: This variable shouldn't be tracked or updated in our side, because of this, we don't care of it's value.
+//  { "SQL_CHARACTER_SET_DATABASE",   "character_set_database",   "CHARACTER_SET_DATABASE",              "'latin2'" },
+
+	{ "SQL_SAFE_UPDATES",             "sql_safe_updates",         "SQL_SAFE_UPDATES",                    "'ON'" },
+	{ "SQL_SELECT_LIMIT",             "sql_select_limit",         "SQL_SELECT_LIMIT",                    "2020" },
+	{ "SQL_SQL_MODE",                 "sql_mode",                 "SQL_MODE",                            "'PIPES_AS_CONCAT,NO_ENGINE_SUBSTITUTION'" },
+	{ "SQL_TIME_ZONE",                "time_zone",                "TIME_ZONE",                           "'-03:00'"},
+	{ "SQL_CHARACTER_SET_RESULTS",    "character_set_results",    "CHARACTER_SET_RESULTS",               "binary" },
+	{ "SQL_CHARACTER_SET_CONNECTION", "character_set_connection", "CHARACTER_SET_CONNECTION",            "'latin1'" },
+	{ "SQL_CHARACTER_SET_CLIENT",     "character_set_client",     "CHARACTER_SET_CLIENT",                "'latin7'" },
+	{ "SQL_ISOLATION_LEVEL",          "transaction_isolation",    "SESSION TRANSACTION ISOLATION LEVEL", "READ COMMITTED"},
+	{ "SQL_TRANSACTION_READ",         "transaction_read_only",    "SESSION TRANSACTION READ",            "ONLY"},
+	{ "SQL_SQL_AUTO_IS_NULL",         "sql_auto_is_null",         "SQL_AUTO_IS_NULL",                    "'ON'"},
+	{ "SQL_COLLATION_CONNECTION",     "collation_connection",     "COLLATION_CONNECTION",                "'latin5_turkish_ci'" },
+	{ "SQL_NET_WRITE_TIMEOUT",        "net_write_timeout",        "NET_WRITE_TIMEOUT",                   "60" },
+	{ "SQL_MAX_JOIN_SIZE",            "max_join_size",            "MAX_JOIN_SIZE",                       "10000" },
+	{ "SQL_LOG_BIN",                  "sql_log_bin",              "SQL_LOG_BIN",                         "0" },
+	{ "SQL_GROUP_CONCAT_MAX_LEN",     "group_concat_max_len",     "GROUP_CONCAT_MAX_LEN",                "4096" },
+	{ "SET_SESSION_TRACK_GTIDS",      "session_track_gtids",      "SESSION_TRACK_GTIDS",                 "OWN_GTID" },
+};
+
+std::vector<std::string> special_syntax_ids {
+	"SQL_CHARACTER_SET", "SQL_SET_NAMES", "SQL_ISOLATION_LEVEL", "SQL_TRANSACTION_READ"
+};
+
+int set_tracked_variables(MYSQL* proxysql) {
+	for (const auto tracked_var_spec : tracked_vars) {
+		std::string set_command { "SET " };
+
+		const std::string var_id = std::get<0>(tracked_var_spec);
+		const std::string var_command = std::get<2>(tracked_var_spec);
+		const std::string var_val = std::get<3>(tracked_var_spec);
+
+		if (std::find(special_syntax_ids.begin(), special_syntax_ids.end(), var_id) == special_syntax_ids.end()) {
+			set_command += var_command + "=" + var_val;
+		} else {
+			set_command += var_command + " " + var_val;
+		}
+
+		MYSQL_QUERY(proxysql, set_command.c_str());
+	}
+
+	return EXIT_SUCCESS;
+}
+
+void parse_internal_session_result(MYSQL_RES *result, json& j) {
+	if(!result) return;
+	MYSQL_ROW row = NULL;
+
+	while ((row = mysql_fetch_row(result))) {
+		j = json::parse(row[0]);
+	}
+}
+
+/**
+ * TODO: Almost identical to 'set_testing-t.cpp', needs a refactor.
+ */
+int query_internal_session(MYSQL *mysql, nlohmann::json& j) {
+	char *query = (char*)"PROXYSQL INTERNAL SESSION";
+	MYSQL_QUERY(mysql, query);
+
+	MYSQL_RES *result = mysql_store_result(mysql);
+	parse_internal_session_result(result, j);
+	mysql_free_result(result);
+
+	// value types in mysql and in proxysql are different
+	// we should convert proxysql values to mysql format to compare
+	for (auto& el : j.items()) {
+		if (el.key() == "conn") {
+			std::string sql_log_bin_value;
+
+			// sql_log_bin {0|1}
+			if (el.value()["sql_log_bin"] == 1) {
+				el.value().erase("sql_log_bin");
+				j["conn"]["sql_log_bin"] = "ON";
+			}
+			else if (el.value()["sql_log_bin"] == 0) {
+				el.value().erase("sql_log_bin");
+				j["conn"]["sql_log_bin"] = "OFF";
+			}
+
+			// sql_auto_is_null {true|false}
+			if (!el.value()["sql_auto_is_null"].dump().compare("ON") ||
+				!el.value()["sql_auto_is_null"].dump().compare("1") ||
+				!el.value()["sql_auto_is_null"].dump().compare("on") ||
+				el.value()["sql_auto_is_null"] == 1
+			) {
+				el.value().erase("sql_auto_is_null");
+				j["conn"]["sql_auto_is_null"] = "ON";
+			}
+			else if (!el.value()["sql_auto_is_null"].dump().compare("OFF") ||
+					!el.value()["sql_auto_is_null"].dump().compare("0") ||
+					!el.value()["sql_auto_is_null"].dump().compare("off") ||
+					el.value()["sql_auto_is_null"] == 0) {
+				el.value().erase("sql_auto_is_null");
+				j["conn"]["sql_auto_is_null"] = "OFF";
+			}
+
+			// sql_safe_updates
+			if (!el.value()["sql_safe_updates"].dump().compare("\"ON\"") ||
+					!el.value()["sql_safe_updates"].dump().compare("\"1\"") ||
+					!el.value()["sql_safe_updates"].dump().compare("\"on\"") ||
+					el.value()["sql_safe_updates"] == 1) {
+				el.value().erase("sql_safe_updates");
+				j["conn"]["sql_safe_updates"] = "ON";
+			} else if (!el.value()["sql_safe_updates"].dump().compare("\"OFF\"") ||
+					!el.value()["sql_safe_updates"].dump().compare("\"0\"") ||
+					!el.value()["sql_safe_updates"].dump().compare("\"off\"") ||
+					el.value()["sql_safe_updates"] == 0) {
+				el.value().erase("sql_safe_updates");
+				j["conn"]["sql_safe_updates"] = "OFF";
+			}
+
+			// sql_select_limit
+			if (!el.value()["sql_select_limit"].dump().compare("\"DEFAULT\"")) {
+				el.value().erase("sql_select_limit");
+				std::stringstream ss {};
+				ss << 0xFFFFFFFFFFFFFFFF;
+				j["conn"]["sql_select_limit"] = ss.str();
+			}
+
+			{
+				// transaction_isolation (level)
+				if (!el.value()["isolation_level"].dump().compare("\"REPEATABLE READ\"")) {
+					el.value().erase("isolation_level");
+					j["conn"]["transaction_isolation"] = "REPEATABLE-READ";
+				}
+				else if (!el.value()["isolation_level"].dump().compare("\"READ COMMITTED\"")) {
+					el.value().erase("isolation_level");
+					j["conn"]["transaction_isolation"] = "READ-COMMITTED";
+				}
+				else if (!el.value()["isolation_level"].dump().compare("\"READ UNCOMMITTED\"")) {
+					el.value().erase("isolation_level");
+					j["conn"]["transaction_isolation"] = "READ-UNCOMMITTED";
+				}
+				else if (!el.value()["isolation_level"].dump().compare("\"SERIALIZABLE\"")) {
+					el.value().erase("isolation_level");
+					j["conn"]["transaction_isolation"] = "SERIALIZABLE";
+				} else {
+					el.value().erase("isolation_level");
+					j["conn"]["transaction_isolation"] = "";
+				}
+			}
+
+			{
+				// transaction_read (write|only)
+				if (!el.value()["transaction_read"].dump().compare("\"ONLY\"")) {
+					el.value().erase("transaction_read");
+					j["conn"]["transaction_read_only"] = "ON";
+				}
+				else if (!el.value()["transaction_read"].dump().compare("\"WRITE\"")) {
+					el.value().erase("transaction_read");
+					j["conn"]["transaction_read_only"] = "OFF";
+				} else {
+					el.value().erase("transaction_read");
+					j["conn"]["transaction_read_only"] = "";
+				}
+			}
+
+			{
+				// session_track_gtids
+				if (!el.value()["session_track_gtids"].dump().compare("\"OFF\"")) {
+					el.value().erase("session_track_gtids");
+					j["conn"]["session_track_gtids"] = "OFF";
+				}
+				else if (!el.value()["session_track_gtids"].dump().compare("\"OWN_GTID\"")) {
+					el.value().erase("session_track_gtids");
+					j["conn"]["session_track_gtids"] = "OWN_GTID";
+				}
+				else if (!el.value()["session_track_gtids"].dump().compare("\"ALL_GTIDS\"")) {
+					el.value().erase("session_track_gtids");
+					j["conn"]["session_track_gtids"] = "ALL_GTIDS";
+				}
+			}
+		}
+	}
+
+	return EXIT_SUCCESS;
+}
+
+using session_var = std::pair<std::string, std::string>;
+
+const std::vector<std::pair<std::string, std::string>> dummy_session_variables {
+	{ "@session_var0", "'foobar0'" },
+	{ "@session_var1", "'foobar1'" },
+	{ "@session_var2", "'foobar2'" },
+	{ "@session_var3", "'foobar3'" },
+};
+
+int set_session_variables(MYSQL* proxysql) {
+	for (const auto sess_var : dummy_session_variables) {
+		const std::string set_command { "SET " + sess_var.first + "=" + sess_var.second };
+		MYSQL_QUERY(proxysql, set_command.c_str());
+	}
+
+	return EXIT_SUCCESS;
+}
+
+int get_session_variables(MYSQL* proxysql, std::vector<session_var>& sess_vars) {
+	std::string select_query { "SELECT /*+ ;hostgroup=0 */ " };
+
+	for (const auto& sess_var : dummy_session_variables) {
+		select_query += sess_var.first;
+
+		if (&sess_var != &dummy_session_variables.back()) {
+			select_query += ",";
+		}
+	}
+
+	MYSQL_QUERY(proxysql, select_query.c_str());
+
+	// Extract the values for the variables
+	std::vector<session_var> tmp_sess_vars {};
+	MYSQL_RES* my_res = mysql_store_result(proxysql);
+	int var_num = mysql_num_fields(my_res);
+	MYSQL_ROW row = mysql_fetch_row(my_res);
+
+	if (row != NULL) {
+		for (int i = 0; i < var_num; i++) {
+			tmp_sess_vars.push_back({ dummy_session_variables[i].first, row[i] == NULL ? "NULL" : row[i] });
+		}
+	}
+
+	mysql_free_result(my_res);
+	sess_vars = tmp_sess_vars;
+
+	return EXIT_SUCCESS;
+}
+
+int get_tracked_proxy_vars(MYSQL* proxysql, const std::vector<std::string>& vars_names, std::vector<var_val>& vars_vals) {
+	nlohmann::json internal_status_json {};
+	int status_err = query_internal_session(proxysql, internal_status_json);
+	if (status_err != EXIT_SUCCESS) {
+		diag("'query_internal_session' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, status_err);
+		return status_err;
+	}
+
+	for (const auto& var_id : vars_names) {
+		const auto conn_object = internal_status_json["conn"];
+		std::string lower_var_id {};
+		std::transform(
+			std::begin(var_id), std::end(var_id), std::back_inserter(lower_var_id),
+			[] (unsigned char c) { return std::tolower(c); }
+		);
+
+		const auto var_key = conn_object.find(lower_var_id);
+		if (var_key == conn_object.end()) {
+			diag("Failed to find key '%s' in the keys reported by 'PROXYSQL INTERNAL SESSION'", lower_var_id.c_str());
+			return EXIT_FAILURE;
+		} else {
+			vars_vals.push_back({ var_id, var_key.value() });
+		}
+	}
+
+	return EXIT_SUCCESS;
+}
+
+int get_default_trx_isolation_attr(const std::string& user_attributes, std::string& trx_isolation) {
+	try {
+		if (user_attributes.empty() == false) {
+			nlohmann::json j_user_attributes = nlohmann::json::parse(user_attributes);
+			std::string tmp_trx_isolation = j_user_attributes["default-transaction_isolation"];
+			if (tmp_trx_isolation == "REPEATABLE READ") {
+				tmp_trx_isolation = "REPEATABLE-READ";
+			} else if (tmp_trx_isolation == "READ COMMITTED") {
+				tmp_trx_isolation = "READ-COMMITTED";
+			} else if (tmp_trx_isolation == "READ UNCOMMITTED") {
+				tmp_trx_isolation = "READ-UNCOMMITTED";
+			} else {
+				tmp_trx_isolation = "";
+			}
+
+			trx_isolation = tmp_trx_isolation;
+		} else {
+			return EXIT_SUCCESS;
+		}
+	} catch(const std::exception& ex) {
+		diag(
+			"Parsing JSON in 'user_attributes' resulted in exception '%s' at ('%s':'%d')",
+			ex.what(), __FILE__, __LINE__
+		);
+		return EXIT_FAILURE;
+	}
+
+	return EXIT_SUCCESS;
+}
+
+int test_simple_select_after_reset(MYSQL* proxysql, const CommandLine&, const std::vector<user_config>& user_configs, bool com_reset=true) {
+	// Do an initial reset
+	if (com_reset) {
+		int err_code = mysql_reset_connection(proxysql);
+		if (err_code != EXIT_SUCCESS) {
+			diag(
+				"'mysql_reset_connection' failed with error: (%d,'%s') at ('%s':'%d')",
+				mysql_errno(proxysql), mysql_error(proxysql), __FILE__, __LINE__
+			);
+			return EXIT_FAILURE;
+		}
+	} else {
+		if (user_configs.size() == 0) {
+			diag("Supplied empty 'users_config' parameter ('%s':'%d')", __FILE__, __LINE__);
+			return EXIT_FAILURE;
+		} else {
+			std::string username = std::get<0>(user_configs[0]);
+			std::string password = std::get<1>(user_configs[0]);
+
+			int err_code = mysql_change_user(proxysql, username.c_str(), password.c_str(), NULL);
+			if (err_code != EXIT_SUCCESS) {
+				diag(
+					"'mysql_change_user' failed with error: (%d,'%s') at ('%s':'%d')",
+					mysql_errno(proxysql), mysql_error(proxysql), __FILE__, __LINE__
+				);
+				return EXIT_FAILURE;
+			}
+		}
+	}
+
+	MYSQL_QUERY(proxysql, "DO 1");
+
+	// Check that a simple select works
+	int err_code = mysql_query(proxysql, "SELECT /*+ ;hostgroup=0 */ 1");
+	if (err_code != EXIT_SUCCESS) {
+		diag("Simple 'SELECT 1' query failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return EXIT_FAILURE;
+	}
+
+	MYSQL_RES* select_res = mysql_store_result(proxysql);
+	mysql_free_result(select_res);
+
+	return EXIT_SUCCESS;
+}
+
+int test_simple_reset_admin(MYSQL*, const CommandLine& cl, const std::vector<user_config>&, bool) {
+	MYSQL* admin = mysql_init(NULL);
+	int res = EXIT_FAILURE;
+
+	if (
+		!mysql_real_connect(
+			admin, "127.0.0.1", cl.admin_username, cl.admin_password, "information_schema", cl.admin_port, NULL, 0
+		)
+	) {
+		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(admin));
+		return EXIT_FAILURE;
+	}
+
+	// FIXME: 'COM_CHANGE_USER' doesn't return proper error right now for unsupported sessions types.
+	mysql_reset_connection(admin);
+
+	if (mysql_errno(admin) == 1047) {
+		res = EXIT_SUCCESS;
+	} else {
+		diag(
+			"'mysql_reset_connection' should fail for 'PROXYSQL_ADMIN' session: (exp_err: '1047', err: '%d', err_msg: '%s')",
+			mysql_errno(admin), mysql_error(admin)
+		);
+	}
+
+	mysql_close(admin);
+	return res;
+}
+
+int test_transaction_rollback(MYSQL* proxysql, const CommandLine&, const std::vector<user_config>& user_configs, bool com_reset=true) {
+	MYSQL_QUERY(proxysql, "DROP TABLE IF EXISTS test.com_reset_connection_trx");
+	MYSQL_QUERY(
+		proxysql,
+		"CREATE TABLE test.com_reset_connection_trx ("
+		" `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `k` int(10) unsigned NOT NULL DEFAULT '0',"
+		" `c` char(120) NOT NULL DEFAULT '', `pad` char(60) NOT NULL DEFAULT '', PRIMARY KEY (`id`), KEY `k_1` (`k`)"
+		")"
+	);
+
+	MYSQL_QUERY(proxysql, "BEGIN");
+	MYSQL_QUERY(proxysql, "INSERT INTO test.com_reset_connection_trx (k, c, pad) VALUES (5, 'k_value', 'value_pad')");
+
+	if (com_reset) {
+		int err_code = mysql_reset_connection(proxysql);
+		if (err_code != EXIT_SUCCESS) {
+			diag(
+				"'mysql_reset_connection' failed with error: (%d,'%s') at ('%s':'%d')",
+				mysql_errno(proxysql), mysql_error(proxysql), __FILE__, __LINE__
+			);
+			return EXIT_FAILURE;
+		}
+	} else {
+		if (user_configs.size() == 0) {
+			diag("Supplied empty 'users_config' parameter ('%s':'%d')", __FILE__, __LINE__);
+			return EXIT_FAILURE;
+		} else {
+			std::string username = std::get<0>(user_configs[0]);
+			std::string password = std::get<1>(user_configs[0]);
+
+			int err_code = mysql_change_user(proxysql, username.c_str(), password.c_str(), NULL);
+			if (err_code != EXIT_SUCCESS) {
+				diag(
+					"'mysql_change_user' failed with error: (%d,'%s') at ('%s':'%d')",
+					mysql_errno(proxysql), mysql_error(proxysql), __FILE__, __LINE__
+				);
+				return EXIT_FAILURE;
+			}
+		}
+	}
+
+	MYSQL_QUERY(proxysql, "SELECT /*+ ;hostgroup=0 */ * FROM test.com_reset_connection_trx");
+	MYSQL_RES* select_res = mysql_store_result(proxysql);
+	int row_count = mysql_num_rows(select_res);
+	if (row_count != 0) {
+		diag(
+			"Transaction should have been 'ROLLBACK', no rows should be returned: (row_count:'%d')", row_count
+		);
+		return EXIT_FAILURE;
+	}
+	mysql_free_result(select_res);
+
+	return EXIT_SUCCESS;
+}
+
+int test_tracked_variables_cleanup(MYSQL* proxysql, const CommandLine&, const std::vector<user_config>& user_configs, bool com_reset=true) {
+	// Get the initial values for the tracked variables
+	std::vector<std::string> var_names {};
+	std::transform(
+		tracked_vars.begin(), tracked_vars.end(), std::back_inserter(var_names),
+		[] (const track_variable_spec& var_spec) -> std::string {
+			return std::get<1>(var_spec);
+		}
+	);
+
+	MYSQL_QUERY(proxysql, "DO 1");
+
+	std::vector<var_val> bef_vars_vals {};
+	int err_num = get_tracked_proxy_vars(proxysql, var_names, bef_vars_vals);
+	if (err_num) {
+		diag("'get_tracked_vars_proxy_vals' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_num);
+		return EXIT_FAILURE;
+	}
+
+	// Do an initial reset
+	if (com_reset) {
+		int err_code = mysql_reset_connection(proxysql);
+		if (err_code != EXIT_SUCCESS) {
+			diag(
+				"'mysql_reset_connection' failed with error: (%d,'%s') at ('%s':'%d')",
+				mysql_errno(proxysql), mysql_error(proxysql), __FILE__, __LINE__
+			);
+			return EXIT_FAILURE;
+		}
+	} else {
+		if (user_configs.size() == 0) {
+			diag("Supplied empty 'users_config' parameter ('%s':'%d')", __FILE__, __LINE__);
+			return EXIT_FAILURE;
+		} else {
+			std::string username = std::get<0>(user_configs[0]);
+			std::string password = std::get<1>(user_configs[0]);
+
+			int err_code = mysql_change_user(proxysql, username.c_str(), password.c_str(), NULL);
+			if (err_code != EXIT_SUCCESS) {
+				diag(
+					"'mysql_change_user' failed with error: (%d,'%s') at ('%s':'%d')",
+					mysql_errno(proxysql), mysql_error(proxysql), __FILE__, __LINE__
+				);
+				return EXIT_FAILURE;
+			}
+		}
+	}
+
+	std::vector<var_val> init_proxy_vars {};
+	int err_code = get_tracked_proxy_vars(proxysql, var_names, init_proxy_vars);
+	if (err_code) {
+		diag("'get_tracked_vars_proxy_vals' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return EXIT_FAILURE;
+	}
+
+	std::vector<var_val> init_mysql_vars {};
+	err_code = get_tracked_mysql_vars(proxysql, init_mysql_vars);
+	if (err_code) {
+		diag("'query_tracked_variables' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return EXIT_FAILURE;
+	}
+
+	// Set new values for the tracked variables
+	err_code = set_tracked_variables(proxysql);
+	if (err_code != EXIT_SUCCESS) {
+		diag("'set_tracked_variables' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return err_code;
+	}
+
+	std::vector<var_val> upd_proxy_vars {};
+	err_code = get_tracked_proxy_vars(proxysql, var_names, upd_proxy_vars);
+	if (err_code) {
+		diag("'get_tracked_vars_proxy_vals' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return EXIT_FAILURE;
+	}
+
+	std::vector<var_val> upd_mysql_vars {};
+	err_code = get_tracked_mysql_vars(proxysql, upd_mysql_vars);
+	if (err_code) {
+		diag("'query_tracked_variables' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return EXIT_FAILURE;
+	}
+
+	// Sort the vectors with the values
+	std::sort(upd_proxy_vars.begin(), upd_proxy_vars.end());
+	std::sort(upd_mysql_vars.begin(), upd_mysql_vars.end());
+
+	bool upd_vars_match =
+		std::equal(std::begin(upd_proxy_vars), std::end(upd_proxy_vars), std::begin(upd_mysql_vars));
+	if (upd_vars_match == false) {
+		diag(
+			"Updated variable values differ from ProxySQL and MySQL: \nProxySQL: %s, \nMySQL: %s",
+			nlohmann::json(upd_proxy_vars).dump().c_str(), nlohmann::json(upd_mysql_vars).dump().c_str()
+		);
+		return EXIT_FAILURE;
+	}
+
+	// Do a second reset and get the new values
+	if (com_reset) {
+		int err_code = mysql_reset_connection(proxysql);
+		if (err_code != EXIT_SUCCESS) {
+			diag(
+				"'mysql_reset_connection' failed with error: (%d,'%s') at ('%s':'%d')",
+				mysql_errno(proxysql), mysql_error(proxysql), __FILE__, __LINE__
+			);
+			return EXIT_FAILURE;
+		}
+	} else {
+		if (user_configs.size() != 2) {
+			diag("Supplied 'users_config' parameters should be of size '2': ('%s':'%d')", __FILE__, __LINE__);
+			return EXIT_FAILURE;
+		} else {
+			std::string username = std::get<0>(user_configs[1]);
+			std::string password = std::get<1>(user_configs[1]);
+
+			int err_code = mysql_change_user(proxysql, username.c_str(), password.c_str(), NULL);
+			if (err_code != EXIT_SUCCESS) {
+				diag(
+					"'mysql_change_user' failed with error: (%d,'%s') at ('%s':'%d')",
+					mysql_errno(proxysql), mysql_error(proxysql), __FILE__, __LINE__
+				);
+				return EXIT_FAILURE;
+			}
+		}
+	}
+
+	std::vector<var_val> reset_proxy_vars {};
+	err_code = get_tracked_proxy_vars(proxysql, var_names, reset_proxy_vars);
+	if (err_code) {
+		diag("'get_tracked_vars_proxy_vals' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return EXIT_FAILURE;
+	}
+
+	std::vector<var_val> reset_mysql_vars {};
+	err_code = get_tracked_mysql_vars(proxysql, reset_mysql_vars);
+	if (err_code) {
+		diag("'query_tracked_variables' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return EXIT_FAILURE;
+	}
+
+	// Sort the vectors with the values
+	std::sort(init_proxy_vars.begin(), init_proxy_vars.end());
+	std::sort(reset_proxy_vars.begin(), reset_proxy_vars.end());
+	std::sort(reset_mysql_vars.begin(), reset_mysql_vars.end());
+
+	// Check that **ANY** of the reset values matched the updated values
+	bool preserved_values = std::any_of(std::begin(upd_proxy_vars), std::end(upd_proxy_vars),
+		[&] (const var_val& var_1) -> bool {
+			for (const auto& var_2 : reset_proxy_vars) {
+				if (var_1 == var_2) return true;
+			}
+
+			return false;
+		}
+	);
+
+	const auto vars_eq_check =
+		[&com_reset](const var_val& var_1, const var_val& var_2) -> bool {
+			if (var_1.first == "transaction_isolation" && com_reset == false) {
+				return var_1.second == "REPEATABLE-READ" && var_2.second == "READ-UNCOMMITTED";
+			} else {
+				return var_1 == var_2;
+			}
+		};
+
+	bool equal_proxy_vars =
+		std::equal(std::begin(init_proxy_vars), std::end(init_proxy_vars), std::begin(reset_proxy_vars), vars_eq_check);
+	bool equal_mysql_vars =
+		std::equal(std::begin(init_mysql_vars), std::end(init_mysql_vars), std::begin(reset_mysql_vars), vars_eq_check);
+	bool reset_values_match = equal_proxy_vars && equal_mysql_vars && (preserved_values == false);
+
+	diag(
+		"Reset variables values are the same as the ones after initial reset ('%d', '%d', '%d'):"
+		" \nBEFORE: %s,\nPROXY_INIT: %s,\nBACKEND_INIT: %s,\nPROXY_UPD: %s,\nPROXY_RESET: %s, \nBACKEND_RESET: %s",
+		equal_proxy_vars, equal_mysql_vars, preserved_values, json(bef_vars_vals).dump().c_str(),
+		json(init_proxy_vars).dump().c_str(), json(init_mysql_vars).dump().c_str(), json(upd_proxy_vars).dump().c_str(),
+		json(reset_proxy_vars).dump().c_str(),  json(reset_mysql_vars).dump().c_str()
+	);
+
+	return reset_values_match ? 0 : 1;
+}
+
+int test_user_defined_variables_cleanup(MYSQL* proxysql, const CommandLine&, const std::vector<user_config>& user_configs, bool com_reset=true) {
+	// Do an initial reset
+	if (com_reset) {
+		int err_code = mysql_reset_connection(proxysql);
+		if (err_code != EXIT_SUCCESS) {
+			diag(
+				"'mysql_reset_connection' failed with error: (%d,'%s') at ('%s':'%d')",
+				mysql_errno(proxysql), mysql_error(proxysql), __FILE__, __LINE__
+			);
+			return EXIT_FAILURE;
+		}
+	} else {
+		if (user_configs.size() == 0) {
+			diag("Supplied empty 'users_config' parameter ('%s':'%d')", __FILE__, __LINE__);
+			return EXIT_FAILURE;
+		} else {
+			std::string username = std::get<0>(user_configs[0]);
+			std::string password = std::get<1>(user_configs[0]);
+
+			int err_code = mysql_change_user(proxysql, username.c_str(), password.c_str(), NULL);
+			if (err_code != EXIT_SUCCESS) {
+				diag(
+					"'mysql_change_user' failed with error: (%d,'%s') at ('%s':'%d')",
+					mysql_errno(proxysql), mysql_error(proxysql), __FILE__, __LINE__
+				);
+				return EXIT_FAILURE;
+			}
+		}
+	}
+
+	// Session variables should be now NULL now
+	std::vector<session_var> ini_sess_vars {};
+	int err_code = get_session_variables(proxysql, ini_sess_vars);
+	if (err_code) {
+		diag("'get_session_variables' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return err_code;
+	}
+
+	bool non_null_val = std::any_of(
+		std::begin(ini_sess_vars), std::end(ini_sess_vars),
+		[](const session_var& sess_var) { return sess_var.second != "NULL"; }
+	);
+	if (non_null_val) {
+		diag(
+			"Session variable values failed to be NULL after initial reset at ('%s':'%d')",
+			__FILE__, __LINE__
+		);
+		return EXIT_FAILURE;
+	}
+
+	err_code = set_session_variables(proxysql);
+	if (err_code) {
+		diag("'set_session_variables' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return err_code;
+	}
+
+	std::vector<session_var> set_sess_vars {};
+	err_code = get_session_variables(proxysql, set_sess_vars);
+	if (err_code) {
+		diag("'get_session_variables' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return err_code;
+	}
+
+	bool equal_sess_values = std::equal(
+		std::begin(dummy_session_variables), std::end(dummy_session_variables), std::begin(set_sess_vars),
+		[] (const session_var& exp_var, const session_var& act_var) {
+			return exp_var.first == act_var.first && exp_var.second == "'" + act_var.second + "'";
+		}
+	);
+	if (equal_sess_values == false) {
+		diag(
+			"Session values failed to be equal to expected set values: \nExp: %s,\nAct: %s",
+			 nlohmann::json(dummy_session_variables).dump().c_str(), nlohmann::json(set_sess_vars).dump().c_str()
+		);
+		return EXIT_FAILURE;
+	}
+
+	// Do a final reset and check that the variables are NULL again
+	if (com_reset) {
+		int err_code = mysql_reset_connection(proxysql);
+		if (err_code != EXIT_SUCCESS) {
+			diag(
+				"'mysql_reset_connection' failed with error: (%d,'%s') at ('%s':'%d')",
+				mysql_errno(proxysql), mysql_error(proxysql), __FILE__, __LINE__
+			);
+			return EXIT_FAILURE;
+		}
+	} else {
+		if (user_configs.size() != 2) {
+			diag("Supplied 'users_config' parameters should be of size '2': ('%s':'%d')", __FILE__, __LINE__);
+			return EXIT_FAILURE;
+		} else {
+			std::string username = std::get<0>(user_configs[1]);
+			std::string password = std::get<1>(user_configs[1]);
+
+			int err_code = mysql_change_user(proxysql, username.c_str(), password.c_str(), NULL);
+			if (err_code != EXIT_SUCCESS) {
+				diag(
+					"'mysql_change_user' failed with error: (%d,'%s') at ('%s':'%d')",
+					mysql_errno(proxysql), mysql_error(proxysql), __FILE__, __LINE__
+				);
+				return EXIT_FAILURE;
+			}
+		}
+	}
+
+	std::vector<session_var> reset_sess_vars {};
+	err_code = get_session_variables(proxysql, reset_sess_vars);
+	if (err_code) {
+		diag("'get_session_variables' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return err_code;
+	}
+
+	non_null_val = std::any_of(
+		std::begin(ini_sess_vars), std::end(ini_sess_vars),
+		[](const session_var& sess_var) { return sess_var.second != "NULL"; }
+	);
+	if (non_null_val) {
+		diag(
+			"Session variable values failed to be NULL after initial reset at ('%s':'%d')",
+			__FILE__, __LINE__
+		);
+		return EXIT_FAILURE;
+	}
+
+	return EXIT_SUCCESS;
+}
+
+int test_recover_session_values(MYSQL* proxysql, const CommandLine& cl, const std::vector<user_config>& user_configs, bool com_reset=true) {
+	std::string username = std::get<0>(user_configs[0]);
+	std::string password = std::get<1>(user_configs[0]);
+
+	int err_code = mysql_change_user(proxysql, username.c_str(), password.c_str(), NULL);
+	if (err_code != EXIT_SUCCESS) {
+		diag(
+			"'mysql_change_user' executed with error: (%d,'%s') at ('%s':'%d')",
+			mysql_errno(proxysql), mysql_error(proxysql), __FILE__, __LINE__
+		);
+		return EXIT_FAILURE;
+	}
+
+	// Get the current session values
+	nlohmann::json internal_status_json {};
+	err_code = query_internal_session(proxysql, internal_status_json);
+	if (err_code != EXIT_SUCCESS) {
+		diag("'query_internal_session' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return err_code;
+	}
+
+	int init_current_hostgroup = internal_status_json["current_hostgroup"].get<int>();
+	bool init_transaction_persistent = internal_status_json["transaction_persistent"].get<bool>();
+	std::string user_attributes = internal_status_json["user_attributes"].get<std::string>();
+
+	std::string init_trx_isolation_attr {};
+	err_code = get_default_trx_isolation_attr(user_attributes, init_trx_isolation_attr);
+	if (err_code != EXIT_SUCCESS) {
+		diag("'get_default_trx_isolation_attr' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return err_code;
+	}
+
+	nlohmann::json j_init_trx_isolation_json = internal_status_json["conn"]["transaction_isolation"];
+	std::string init_trx_isolation_session { j_init_trx_isolation_json.empty() ? "" : j_init_trx_isolation_json };
+
+	if (init_trx_isolation_attr != init_trx_isolation_session) {
+		diag(
+			"Found invalid session 'trx_isolation' not matching 'user_attributes' (Exp:'%s', Act:'%s') at ('%s':'%d')",
+			init_trx_isolation_attr.c_str(), init_trx_isolation_session.c_str(), __FILE__, __LINE__
+		);
+		return EXIT_FAILURE;
+	}
+
+	// Reset the connection
+	if (com_reset) {
+		int err_code = mysql_reset_connection(proxysql);
+		if (err_code != EXIT_SUCCESS) {
+			diag(
+				"'mysql_reset_connection' failed with error: (%d,'%s') at ('%s':'%d')",
+				mysql_errno(proxysql), mysql_error(proxysql), __FILE__, __LINE__
+			);
+			return EXIT_FAILURE;
+		}
+	} else {
+		if (user_configs.size() == 0) {
+			diag("Supplied empty 'users_config' parameter ('%s':'%d')", __FILE__, __LINE__);
+			return EXIT_FAILURE;
+		} else {
+			std::string username = std::get<0>(user_configs[1]);
+			std::string password = std::get<1>(user_configs[1]);
+
+			int err_code = mysql_change_user(proxysql, username.c_str(), password.c_str(), NULL);
+			if (err_code != EXIT_SUCCESS) {
+				diag(
+					"'mysql_change_user' executed with error: (%d,'%s') at ('%s':'%d')",
+					mysql_errno(proxysql), mysql_error(proxysql), __FILE__, __LINE__
+				);
+				return EXIT_FAILURE;
+			}
+		}
+	}
+
+	err_code = query_internal_session(proxysql, internal_status_json);
+	if (err_code != EXIT_SUCCESS) {
+		diag("'query_internal_session' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return err_code;
+	}
+
+	// Update the session values
+	init_current_hostgroup = internal_status_json["current_hostgroup"].get<int>();
+	init_transaction_persistent = internal_status_json["transaction_persistent"].get<bool>();
+	user_attributes = internal_status_json["user_attributes"].get<std::string>();
+
+	std::string upd_trx_isolation_attr {};
+	err_code = get_default_trx_isolation_attr(user_attributes, upd_trx_isolation_attr);
+	if (err_code != EXIT_SUCCESS) {
+		diag("'get_default_trx_isolation_attr' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return err_code;
+	}
+
+	nlohmann::json j_upd_trx_isolation_json = internal_status_json["conn"]["transaction_isolation"];
+	std::string upd_trx_isolation_session { j_upd_trx_isolation_json.empty() ? "" : j_upd_trx_isolation_json };
+
+	if (upd_trx_isolation_attr != upd_trx_isolation_session) {
+		diag(
+			"Found invalid session 'trx_isolation' not matching 'user_attributes' (Exp:'%s', Act:'%s') at ('%s':'%d')",
+			upd_trx_isolation_attr.c_str(), upd_trx_isolation_session.c_str(), __FILE__, __LINE__
+		);
+		return EXIT_FAILURE;
+	}
+
+	int upd_current_hostgroup = internal_status_json["current_hostgroup"].get<int>();
+	bool upd_transaction_persistent = internal_status_json["transaction_persistent"].get<bool>();
+	bool matching_trx_isolations = false;
+
+	if (com_reset == true) {
+		matching_trx_isolations =
+			init_trx_isolation_session == "REPEATABLE-READ" &&
+			upd_trx_isolation_session == "REPEATABLE-READ";
+	} else {
+		matching_trx_isolations =
+			init_trx_isolation_session == "REPEATABLE-READ" &&
+			upd_trx_isolation_session == "READ-UNCOMMITTED";
+	}
+
+	if (
+		init_current_hostgroup != upd_current_hostgroup &&
+		init_transaction_persistent != upd_transaction_persistent &&
+		matching_trx_isolations
+	) {
+		diag(
+			"Values for 'INTERNAL SESSION' variables failed to match expected ones:"
+			" 'current_hostgroup'= (Exp:'%d', Act:'%d'), 'transaction_persistent': (Exp: '%d', Act: '%d')),"
+			" 'isolation_level'= (Exp:'%s', Act:'%s')",
+			init_current_hostgroup, upd_current_hostgroup, init_transaction_persistent, upd_transaction_persistent,
+			init_trx_isolation_session.c_str(), upd_trx_isolation_session.c_str()
+		);
+		return EXIT_FAILURE;
+	} else {
+		return EXIT_SUCCESS;
+	}
+}
+
+int test_mysql_server_variables(MYSQL*, const CommandLine& cl, const std::vector<user_config>& user_configs, bool com_reset=true) {
+	// Do an initial reset
+	MYSQL* mysql = mysql_init(NULL);
+
+	// Use a known default charset for the connection
+	MARIADB_CHARSET_INFO* latin2_charset = proxysql_find_charset_collate("latin2_general_ci");
+	mysql->charset = latin2_charset;
+
+	if (!mysql_real_connect(mysql, cl.host, "root", "root", NULL, 13306, NULL, 0)) {
+		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(mysql));
+		return EXIT_FAILURE;
+	}
+
+	std::vector<var_val> bef_vars_vals {};
+	int err_num = get_tracked_mysql_vars(mysql, bef_vars_vals);
+	if (err_num) {
+		diag("'get_tracked_vars_proxy_vals' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_num);
+		return EXIT_FAILURE;
+	}
+
+	if (com_reset) {
+		int err_code = mysql_reset_connection(mysql);
+		if (err_code != EXIT_SUCCESS) {
+			diag(
+				"'mysql_reset_connection' failed with error: (%d,'%s') at ('%s':'%d')",
+				mysql_errno(mysql), mysql_error(mysql), __FILE__, __LINE__
+			);
+			return EXIT_FAILURE;
+		}
+	} else {
+		if (user_configs.size() == 0) {
+			diag("Supplied empty 'users_config' parameter ('%s':'%d')", __FILE__, __LINE__);
+			return EXIT_FAILURE;
+		} else {
+			std::string username = std::get<0>(user_configs[0]);
+			std::string password = std::get<1>(user_configs[0]);
+
+			int err_code = mysql_change_user(mysql, username.c_str(), password.c_str(), NULL);
+			if (err_code != EXIT_SUCCESS) {
+				diag(
+					"'mysql_change_user' failed with error: (%d,'%s') at ('%s':'%d')",
+					mysql_errno(mysql), mysql_error(mysql), __FILE__, __LINE__
+				);
+				return EXIT_FAILURE;
+			}
+		}
+	}
+
+	std::vector<std::string> var_names {};
+	std::transform(
+		tracked_vars.begin(), tracked_vars.end(), std::back_inserter(var_names),
+		[] (const track_variable_spec& var_spec) -> std::string {
+			return std::get<1>(var_spec);
+		}
+	);
+
+	// Get the initial values for the tracked variables
+	std::vector<var_val> ini_vars_vals {};
+	std::vector<var_val> initial_mysql_vars {};
+	int err_code = get_tracked_mysql_vars(mysql, initial_mysql_vars);
+	if (err_code) {
+		diag("'query_tracked_variables' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return EXIT_FAILURE;
+	}
+
+	// Set new values for the tracked variables
+	err_code = set_tracked_variables(mysql);
+	if (err_code != EXIT_SUCCESS) {
+		diag("'set_tracked_variables' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return err_code;
+	}
+
+	std::vector<var_val> upd_mysql_vars {};
+	err_code = get_tracked_mysql_vars(mysql, upd_mysql_vars);
+	if (err_code) {
+		diag("'query_tracked_variables' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return EXIT_FAILURE;
+	}
+
+	// Sort the vectors with the values
+	std::sort(upd_mysql_vars.begin(), upd_mysql_vars.end());
+
+	// Do a second reset and get the new values
+	if (com_reset) {
+		int err_code = mysql_reset_connection(mysql);
+		if (err_code != EXIT_SUCCESS) {
+			diag(
+				"'mysql_reset_connection' failed with error: (%d,'%s') at ('%s':'%d')",
+				mysql_errno(mysql), mysql_error(mysql), __FILE__, __LINE__
+			);
+			return EXIT_FAILURE;
+		}
+	} else {
+		if (user_configs.size() != 2) {
+			diag("Supplied 'users_config' parameters should be of size '2': ('%s':'%d')", __FILE__, __LINE__);
+			return EXIT_FAILURE;
+		} else {
+			std::string username = std::get<0>(user_configs[1]);
+			std::string password = std::get<1>(user_configs[1]);
+
+			MARIADB_CHARSET_INFO* charset = proxysql_find_charset_collate("latin2_general_ci");
+			mysql->charset = charset;
+
+			int err_code = mysql_change_user(mysql, username.c_str(), password.c_str(), NULL);
+			if (err_code != EXIT_SUCCESS) {
+				diag(
+					"'mysql_change_user' failed with error: (%d,'%s') at ('%s':'%d')",
+					mysql_errno(mysql), mysql_error(mysql), __FILE__, __LINE__
+				);
+				return EXIT_FAILURE;
+			}
+		}
+	}
+
+	std::vector<var_val> reset_mysql_vars {};
+	err_code = get_tracked_mysql_vars(mysql, reset_mysql_vars);
+	if (err_code) {
+		diag("'query_tracked_variables' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return EXIT_FAILURE;
+	}
+
+	// Sort the vectors with the values
+	std::sort(ini_vars_vals.begin(), ini_vars_vals.end());
+	std::sort(reset_mysql_vars.begin(), reset_mysql_vars.end());
+
+	bool reset_values_match =
+		std::equal(std::begin(reset_mysql_vars), std::end(reset_mysql_vars), std::begin(initial_mysql_vars));
+	diag(
+		"Reset variables values are the same as the ones after initial reset:"
+		" \nBACKEND_INIT: %s\nBACKEND_UPD: %s\nBACKEND_RESET: %s",
+		nlohmann::json(initial_mysql_vars).dump().c_str(), nlohmann::json(upd_mysql_vars).dump().c_str(),
+		nlohmann::json(reset_mysql_vars).dump().c_str()
+	);
+
+	mysql_close(mysql);
+
+	return reset_values_match ? 0 : 1;
+}
+
+using test_function = std::function<int(MYSQL*,const CommandLine&,const std::vector<user_config>&,bool)>;
+
+std::vector<std::pair<std::string, test_function>> tests_fns {
+	{ "test_simple_select_after_reset", test_simple_select_after_reset },
+	{ "test_transaction_rollback", test_transaction_rollback },
+	{ "test_tracked_variables_cleanup", test_tracked_variables_cleanup },
+	{ "test_user_defined_variables_cleanup", test_user_defined_variables_cleanup },
+	{ "test_simple_reset_admin", test_simple_reset_admin },
+	{ "test_recover_session_values", test_recover_session_values },
+	// NOTE: This is not a proper test for ProxySQL, was used during development to verify that the
+	// same behavior tested by 'test_tracked_variables_cleanup' holds against a MySQL instance.
+	// { "test_mysql_server_variables", test_mysql_server_variables }
+};
+
+int main(int argc, char** argv) {
+	CommandLine cl;
+
+	// One 'reset_connection' and 'change_user_test'
+	plan(tests_fns.size() * 2);
+
+	if (cl.getEnv()) {
+		diag("Failed to get the required environmental variables.");
+		return EXIT_FAILURE;
+	}
+
+	MYSQL* proxysql = mysql_init(NULL);
+
+	// Use a known default charset for the connection
+	MARIADB_CHARSET_INFO* latin2_charset = proxysql_find_charset_collate("latin2_general_ci");
+	proxysql->charset = latin2_charset;
+
+	if (
+		!mysql_real_connect(
+			proxysql, "127.0.0.1", cl.username, cl.password, "information_schema", cl.port, NULL, 0
+		)
+	) {
+		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql));
+		return EXIT_FAILURE;
+	}
+
+	MYSQL* admin = mysql_init(NULL);
+	if (
+		!mysql_real_connect(
+			admin, "127.0.0.1", cl.admin_username, cl.admin_password, "information_schema", cl.admin_port, NULL, 0
+		)
+	) {
+		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(admin));
+		return EXIT_FAILURE;
+	}
+
+	// Set the number of backend connections to '1' for making sure all the operations are performed in the same
+	// backend connection.
+	std::string t_update_servers_query {
+		"UPDATE mysql_servers SET max_connections=1 WHERE hostgroup_id=%d"
+	};
+	std::string update_servers_query {};
+	string_format(t_update_servers_query, update_servers_query, 0);
+
+	MYSQL_QUERY(admin, update_servers_query.c_str());
+	MYSQL_QUERY(admin, "LOAD MYSQL SERVERS TO RUNTIME");
+
+	usleep(50*1000);
+
+	const std::vector<user_config> extra_users {
+		std::make_tuple(
+			"sbtest_reset_conn_1",
+			"sbtest_reset_conn_1",
+			"{\"default-transaction_isolation\":\"REPEATABLE READ\"}"
+		),
+		std::make_tuple(
+			"sbtest_reset_conn_2",
+			"sbtest_reset_conn_2",
+			"{\"default-transaction_isolation\":\"READ UNCOMMITTED\"}"
+		)
+	};
+
+	MYSQL* mysql_server = mysql_init(NULL);
+	if (!mysql_real_connect(mysql_server, cl.host, "root", "root", NULL, 13306, NULL, 0)) {
+		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(mysql_server));
+		return EXIT_FAILURE;
+	}
+
+	int err_code = create_extra_users(admin, mysql_server, extra_users);
+	if (err_code) {
+		diag("'create_extra_users' failed at ('%s':'%d') with error '%d'", __FILE__, __LINE__, err_code);
+		return EXIT_FAILURE;
+	}
+
+	MYSQL_QUERY(admin, "LOAD MYSQL USERS TO RUNTIME");
+
+	for (const auto& test_fn : tests_fns) {
+		int test_res = EXIT_FAILURE;
+
+		// Test the 'reset_connection' first
+		try {
+			test_res = test_fn.second(proxysql, cl, extra_users, true);
+		} catch (const std::exception& ex) {
+			diag("Exception while executing test '%s', exception msg: '%s'", test_fn.first.c_str(), ex.what());
+		}
+		ok(
+			test_res == EXIT_SUCCESS,
+			"'COM_RESET_CONNECTION' test '%s' completed with error code '%d'", test_fn.first.c_str(), test_res
+		);
+
+		// Test the 'change_user' later
+		try {
+			test_res = test_fn.second(proxysql, cl, extra_users, false);
+		} catch (const std::exception& ex) {
+			diag("Exception while executing test '%s', exception msg: '%s'", test_fn.first.c_str(), ex.what());
+		}
+		ok(
+			test_res == EXIT_SUCCESS,
+			"'COM_CHANGE_USER' test '%s' completed with error code '%d'", test_fn.first.c_str(), test_res
+		);
+	}
+
+	mysql_close(proxysql);
+	mysql_close(mysql_server);
+	mysql_close(admin);
+
+	return exit_status();
+}
diff --git a/test/tap/tests/test_connection_annotation-t.cpp b/test/tap/tests/test_connection_annotation-t.cpp
index 662f9f0ae4..7c8e6a78be 100644
--- a/test/tap/tests/test_connection_annotation-t.cpp
+++ b/test/tap/tests/test_connection_annotation-t.cpp
@@ -71,7 +71,7 @@ int main(int argc, char** argv) {
 	srand(time(NULL));
 	int rand_conn = rand() % 100;
 	for (int i = 0; i < rand_conn; i++) {
-		MYSQL_QUERY(proxysql_mysql, "SELECT /* ;create_new_connection=1 */ 1");
+		MYSQL_QUERY(proxysql_mysql, "SELECT /*+ ;create_new_connection=1 */ 1");
 		proxy_res = mysql_store_result(proxysql_mysql);
 		mysql_free_result(proxy_res);
 	}
diff --git a/test/tap/tests/test_default_value_transaction_isolation_attr-t.cpp b/test/tap/tests/test_default_value_transaction_isolation_attr-t.cpp
index dec96b8202..342205bcbe 100644
--- a/test/tap/tests/test_default_value_transaction_isolation_attr-t.cpp
+++ b/test/tap/tests/test_default_value_transaction_isolation_attr-t.cpp
@@ -50,140 +50,12 @@ void parse_result_json_column(MYSQL_RES *result, json& j) {
 	}
 }
 
-/**
- * @brief Create a MySQL user for testing purposes in the server determined
- *  by supplied *already established* MySQL connection.
- *
- * @param mysql_server An already opened connection to a MySQL server.
- * @param user The name of the user to be created.
- * @param pass The password for the user to be created.
- *
- * @return EXIT_SUCCESS in case of success, EXIT_FAILURE otherwise.
- */
-int create_mysql_user(
-	MYSQL* mysql_server,
-	const std::string& user,
-	const std::string& pass
-) {
-	const std::string t_drop_user_query { "DROP USER IF EXISTS %s@'%%'" };
-	std::string drop_user_query {};
-	string_format(t_drop_user_query, drop_user_query, user.c_str());
-
-	const std::string t_create_user_query {
-		"CREATE USER IF NOT EXISTS %s@'%%' IDENTIFIED WITH 'mysql_native_password' BY \"%s\""
-	};
-	std::string create_user_query {};
-	string_format(t_create_user_query, create_user_query, user.c_str(), pass.c_str());
-
-	const std::string t_grant_usage_query { "GRANT USAGE ON *.* TO %s@'%%'" };
-	std::string grant_usage_query { };
-	string_format(t_grant_usage_query, grant_usage_query, user.c_str());
-
-	MYSQL_QUERY(mysql_server, drop_user_query.c_str());
-	MYSQL_QUERY(mysql_server, create_user_query.c_str());
-	MYSQL_QUERY(mysql_server, grant_usage_query.c_str());
-
-	return EXIT_SUCCESS;
-}
-
-/**
- * @brief Creates the new supplied user in ProxySQL with the provided
- *   attributes.
- *
- * @param proxysql_admin An already opened connection to ProxySQL Admin.
- * @param user The username of the user to be created.
- * @param pass The password of the user to be created.
- * @param attributes The 'attributes' value for the 'attributes' column
- *   for the user to be created.
- *
- * @return EXIT_SUCCESS in case of success, EXIT_FAILURE otherwise.
- */
-int create_proxysql_user(
-	MYSQL* proxysql_admin,
-	const std::string& user,
-	const std::string& pass,
-	const std::string& attributes
-) {
-	std::string t_del_user_query { "DELETE FROM mysql_users WHERE username='%s'" };
-	std::string del_user_query {};
-	string_format(t_del_user_query, del_user_query, user.c_str());
-
-	std::string t_insert_user {
-		"INSERT INTO mysql_users (username,password,active,attributes)"
-		" VALUES ('%s','%s',1,'%s')"
-	};
-	std::string insert_user {};
-	string_format(t_insert_user, insert_user, user.c_str(), pass.c_str(), attributes.c_str());
-
-	MYSQL_QUERY(proxysql_admin, del_user_query.c_str());
-	MYSQL_QUERY(proxysql_admin, insert_user.c_str());
-
-	return EXIT_SUCCESS;
-}
-
-using user_config = std::tuple<std::string, std::string, std::string, std::string>;
-
-/**
- * @brief Create the extra required users for the test in
- *   both MYSQL and ProxySQL.
- *
- * @param proxysql_admin An already opened connection to ProxySQL admin
- *   interface.
- * @param mysql_server An already opened connection to a backend MySQL
- *   server.
- * @param user_attributes The user attributes whose should  be part of user
- *   configuration in ProxySQL side.
- *
- * @return EXIT_SUCCESS in case of success, EXIT_FAILURE otherwise.
- */
-int create_extra_users(
-	MYSQL* proxysql_admin,
-	MYSQL* mysql_server,
-	const std::vector<user_config>& users_config
-) {
-	std::vector<std::pair<std::string, std::string>> v_user_pass {};
-	std::transform(
-		std::begin(users_config),
-		std::end(users_config),
-		std::back_inserter(v_user_pass),
-		[](const user_config& u_config) {
-			return std::pair<std::string, std::string> {
-				std::get<0>(u_config),
-				std::get<1>(u_config)
-			};
-		}
-	);
-
-	// create the MySQL users
-	for (const auto& user_pass : v_user_pass) {
-		int c_user_res =
-			create_mysql_user(mysql_server, user_pass.first, user_pass.second);
-		if (c_user_res) {
-			return c_user_res;
-		}
-	}
-
-	// create the ProxySQL users
-	for (const auto& user_config : users_config) {
-		int c_p_user_res =
-			create_proxysql_user(
-				proxysql_admin,
-				std::get<0>(user_config),
-				std::get<1>(user_config),
-				std::get<2>(user_config)
-			);
-		if (c_p_user_res) {
-			return c_p_user_res;
-		}
-	}
-
-	return EXIT_SUCCESS;
-}
+using user_attributes = std::tuple<std::string, std::string, std::string, std::string>;
 
 /**
  * @brief User names and attributes to be check and verified.
  */
-const std::vector<user_config> c_user_attributes {
+const std::vector<user_attributes> c_user_attributes {
 	std::make_tuple(
 		"sbtest1",
 		"sbtest1",
@@ -377,15 +249,22 @@ int main(int argc, char** argv) {
 	}
 
 	// Creating the new required users
+	std::vector<user_config> users_configs {};
+	std::transform(
+		c_user_attributes.begin(), c_user_attributes.end(), std::back_inserter(users_configs),
+		[] (const user_attributes& u_attr) -> user_config {
+			return make_tuple(std::get<0>(u_attr), std::get<1>(u_attr), std::get<2>(u_attr));
+		}
+	);
 	int c_users_res =
-		create_extra_users(proxysql_admin, mysql_server, c_user_attributes);
+		create_extra_users(proxysql_admin, mysql_server, users_configs);
 	if (c_users_res) { return c_users_res; }
 
 	// Load ProxySQL users to runtime
 	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL USERS TO RUNTIME");
 
 	// Performing the connection checks
-	std::vector<user_config> user_attributes { c_user_attributes };
+	std::vector<user_attributes> user_attributes { c_user_attributes };
 	auto rng = std::default_random_engine {};
 	std::shuffle(std::begin(user_attributes), std::end(user_attributes), rng);
 
diff --git a/test/tap/tests/test_keep_multiplexing_variables-t.cpp b/test/tap/tests/test_keep_multiplexing_variables-t.cpp
deleted file mode 100644
index 2ed9285493..0000000000
--- a/test/tap/tests/test_keep_multiplexing_variables-t.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-/**
- * @file test_keep_multiplexing_variables-t.cpp
- * @brief This test checks that selecting on '@@session.*' and '@@*' variables disables multiplexing when
- *   target variables are not specified by 'mysql-keep_multiplexing_variables'.
- * @date 2021-09-30
- */
-
-#include <vector>
-#include <string>
-#include <stdio.h>
-#include <mysql.h>
-
-#include "tap.h"
-#include "command_line.h"
-#include "utils.h"
-#include "json.hpp"
-
-using std::string;
-using namespace nlohmann;
-
-void parse_result_json_column(MYSQL_RES *result, json& j) {
-	if(!result) return;
-	MYSQL_ROW row;
-
-	while ((row = mysql_fetch_row(result))) {
-		j = json::parse(row[0]);
-	}
-}
-
-std::vector<std::string> select_queries {
-	"select @@session.autocommit,         @@session.big_tables, @@autocommit,@@bulk_insert_buffer_size,     @@character_set_database,@@transaction_isolation,    @@version,@@session.transaction_isolation",
-	"select  @@autocommit, @@sql_mode,        @@big_tables,    @@autocommit,@@bulk_insert_buffer_size,     @@character_set_database,@@session.transaction_isolation,    @@version,@@transaction_isolation",
-	"select  @@autocommit, @@sql_mode,        @@big_tables,    @@autocommit,@@bulk_insert_buffer_size,     @@character_set_database,@@session.transaction_isolation,    @@version,@@transaction_isolation",
-	"select @@autocommit, @@sql_mode,        @@big_tables,    @@autocommit,@@session.bulk_insert_buffer_size,     @@character_set_database,@@session.transaction_isolation,    @@version,@@transaction_isolation",
-	"select  @@sql_mode, @@autocommit,    @@big_tables,    @@autocommit,    @@character_set_database,@@transaction_isolation,    @@version,@@session.transaction_isolation",
-	"select  @@sql_mode, @@autocommit,    @@big_tables,    @@autocommit,@@bulk_insert_buffer_size,     @@transaction_isolation,    @@version,@@session.transaction_isolation",
-	"select  @@sql_mode, @@autocommit,    @@big_tables,    @@autocommit,@@bulk_insert_buffer_size,     @@character_set_database,@@transaction_isolation,    @@version,@@session.transaction_isolation",
-	"select @@session.autocommit, @@big_tables, @@autocommit,@@bulk_insert_buffer_size,     @@character_set_database,@@transaction_isolation,    @@version,@@session.transaction_isolation",
-	"select  @@big_tables, @@session.autocommit, @@autocommit,@@bulk_insert_buffer_size,     @@character_set_database,@@transaction_isolation,    @@version,@@session.transaction_isolation",
-	"select  @@session.autocommit, @@big_tables, @@autocommit,@@bulk_insert_buffer_size,     @@character_set_database,  @@version,@@session.transaction_isolation",
-	"select  @@session.autocommit, @@big_tables, @@autocommit,@@bulk_insert_buffer_size,     @@character_set_database,@@transaction_isolation,    @@version,@@session.transaction_isolation",
-};
-
-int check_multiplexing_disabled(const CommandLine& cl, const std::string query, bool& multiplex_disabled) {
-	MYSQL* proxysql_mysql = mysql_init(NULL);
-
-	if (!mysql_real_connect(proxysql_mysql, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) {
-		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_mysql));
-		return EXIT_FAILURE;
-	}
-
-	MYSQL_QUERY(proxysql_mysql, query.c_str());
-	MYSQL_RES* dummy_res = mysql_store_result(proxysql_mysql);
-	mysql_free_result(dummy_res);
-
-	MYSQL_QUERY(proxysql_mysql, "PROXYSQL INTERNAL SESSION");
-	json j_status {};
-	MYSQL_RES* int_session_res = mysql_store_result(proxysql_mysql);
-	parse_result_json_column(int_session_res, j_status);
-	mysql_free_result(int_session_res);
-
-	if (j_status.contains("backends")) {
-		for (auto& backend : j_status["backends"]) {
-			if (backend != nullptr && backend.contains("conn") && backend["conn"].contains("status")) {
-				multiplex_disabled = backend["conn"]["MultiplexDisabled"];
-			}
-		}
-	}
-
-	mysql_close(proxysql_mysql);
-
-	return EXIT_SUCCESS;
-}
-
-int main(int argc, char** argv) {
-	CommandLine cl;
-
-	if (cl.getEnv()) {
-		diag("Failed to get the required environmental variables.");
-		return EXIT_FAILURE;
-	}
-
-	plan(26);
-
-	MYSQL* proxysql_admin = mysql_init(NULL);
-
-	if (!mysql_real_connect(proxysql_admin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) {
-		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_admin));
-		return EXIT_FAILURE;
-	}
-
-	// Clean the 'keep_multiplexing_variables'
-	MYSQL_QUERY(proxysql_admin, "SET mysql-keep_multiplexing_variables='version'");
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-	diag("Cleaning 'mysql-keep_multiplexing_variables' to check multiplexing disabling.");
-
-	// Check that any query will disable multiplexing
-	{
-		bool disabled_multiplexing = false;
-		int check_multiplexing_err = check_multiplexing_disabled(cl, "SELECT @@sql_mode", disabled_multiplexing);
-		ok (disabled_multiplexing == true, "Simple 'SELECT @@*' should disable multiplexing.");
-	}
-
-	{
-		bool disabled_multiplexing = false;
-		int check_multiplexing_err = check_multiplexing_disabled(cl, "SELECT @@SESSION.sql_mode", disabled_multiplexing);
-		ok (disabled_multiplexing == true, "Simple 'SELECT @@SESSION.*' should disable multiplexing.");
-	}
-
-	// Adding the variable to 'keep_multiplexing_variables' should keep multiplexing enabled
-	MYSQL_QUERY(proxysql_admin, "SET mysql-keep_multiplexing_variables='version,sql_mode'");
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-	diag("Setting 'mysql-keep_multiplexing_variables' to keep multiplexing enabled.");
-
-	// Check that any query will disable multiplexing
-	{
-		bool disabled_multiplexing = false;
-		int check_multiplexing_err = check_multiplexing_disabled(cl, "SELECT @@sql_mode", disabled_multiplexing);
-		ok (disabled_multiplexing == false, "Simple 'SELECT @@*' should keep multiplexing enabled.");
-	}
-
-	{
-		bool disabled_multiplexing = false;
-		int check_multiplexing_err = check_multiplexing_disabled(cl, "SELECT @@SESSION.sql_mode", disabled_multiplexing);
-		ok (disabled_multiplexing == false, "Simple 'SELECT @@SESSION.*' should keep multiplexing enabled.");
-	}
-
-	// Clean the 'keep_multiplexing_variables'
-	MYSQL_QUERY(proxysql_admin, "SET mysql-keep_multiplexing_variables='version'");
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-	diag("Cleaning 'mysql-keep_multiplexing_variables' to check multiplexing disabling.");
-
-	{
-		for (const std::string& query : select_queries) {
-			bool disabled_multiplexing = true;
-			int check_multiplexing_err = check_multiplexing_disabled(cl, query, disabled_multiplexing);
-			ok (disabled_multiplexing == true, "Complex 'SELECT @@SESSION.*, @@*' should disable multiplexing.");
-		}
-	}
-
-	// Adding multiple variables to 'keep_multiplexing_variables' should keep multiplexing enabled
-	MYSQL_QUERY(proxysql_admin, "SET mysql-keep_multiplexing_variables='version,sql_mode,autocommit,big_tables,bulk_insert_buffer_size,character_set_database,transaction_isolation'");
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-	diag("Setting 'mysql-keep_multiplexing_variables' to keep multiplexing enabled.");
-
-	{
-		for (const std::string& query : select_queries) {
-			bool disabled_multiplexing = false;
-			int check_multiplexing_err = check_multiplexing_disabled(cl, query, disabled_multiplexing);
-			ok (disabled_multiplexing == false, "Complex 'SELECT @@SESSION.*, @@*' queries should keep multiplexing enabled.");
-		}
-	}
-
-	mysql_close(proxysql_admin);
-
-	return exit_status();
-}
diff --git a/test/tap/tests/test_mysqlsh-t.cpp b/test/tap/tests/test_mysqlsh-t.cpp
index e8879f207b..98ccaa5c71 100644
--- a/test/tap/tests/test_mysqlsh-t.cpp
+++ b/test/tap/tests/test_mysqlsh-t.cpp
@@ -89,6 +89,8 @@ int main(int argc, char** argv) {
 			} else {
 				ok(false, "Invalid resulset. Expected 'num_fields' = 1, not %d", concat_num_fields);
 			}
+
+			mysql_free_result(concat_res);
 		}
 
 		mysql_free_result(concat_res);
diff --git a/test/tap/tests/test_query_rules_routing-t.cpp b/test/tap/tests/test_query_rules_routing-t.cpp
index 165e08543e..ba5ec6037b 100644
--- a/test/tap/tests/test_query_rules_routing-t.cpp
+++ b/test/tap/tests/test_query_rules_routing-t.cpp
@@ -80,31 +80,31 @@ std::vector<dst_hostgroup_test> dst_hostgroup_tests {
 		},
 		{
 			{
-				"SELECT /* ;%s */ 1",
+				"SELECT /*+ ;%s */ 1",
 				1
 			},
 			{
-				"SELECT /* ;%s */ c FROM test.reg_test_3427_0 WHERE id=1",
+				"SELECT /*+ ;%s */ c FROM test.reg_test_3427_0 WHERE id=1",
 				1
 			},
 			{
-				"SELECT /* ;%s */ c FROM test.reg_test_3427_0 WHERE id BETWEEN 1 AND 20",
+				"SELECT /*+ ;%s */ c FROM test.reg_test_3427_0 WHERE id BETWEEN 1 AND 20",
 				1
 			},
 			{
-				"SELECT /* ;%s */ SUM(k) c FROM test.reg_test_3427_0 WHERE id BETWEEN 1 AND 10",
+				"SELECT /*+ ;%s */ SUM(k) c FROM test.reg_test_3427_0 WHERE id BETWEEN 1 AND 10",
 				1
 			},
 			{
-				"INSERT /* ;%s */ INTO test.reg_test_3427_0 (k) VALUES (2)",
+				"INSERT /*+ ;%s */ INTO test.reg_test_3427_0 (k) VALUES (2)",
 				0
 			},
 			{
-				"UPDATE /* ;%s */ test.reg_test_3427_0 SET pad=\"random\" WHERE id=2",
+				"UPDATE /*+ ;%s */ test.reg_test_3427_0 SET pad=\"random\" WHERE id=2",
 				0
 			},
 			{
-				"SELECT DISTINCT /* ;%s */ c FROM test.reg_test_3427_0 WHERE id BETWEEN 1 AND 10 ORDER BY c",
+				"SELECT DISTINCT /*+ ;%s */ c FROM test.reg_test_3427_0 WHERE id BETWEEN 1 AND 10 ORDER BY c",
 				1
 			}
 		}
@@ -118,23 +118,23 @@ std::vector<dst_hostgroup_test> dst_hostgroup_tests {
 		},
 		{
 			{
-				"UPDATE /* ;%s */ test.reg_test_3427_0 SET pad=\"random\" WHERE id=2",
+				"UPDATE /*+ ;%s */ test.reg_test_3427_0 SET pad=\"random\" WHERE id=2",
 				0
 			},
 			{
-				"SELECT DISTINCT /* ;%s */ c FROM test.reg_test_3427_0 WHERE id BETWEEN 1 AND 10 ORDER BY c",
+				"SELECT DISTINCT /*+ ;%s */ c FROM test.reg_test_3427_0 WHERE id BETWEEN 1 AND 10 ORDER BY c",
 				1
 			},
 			{
-				"SELECT /* ;%s */ c FROM test.reg_test_3427_1 WHERE id BETWEEN 1 AND 10 ORDER BY c",
+				"SELECT /*+ ;%s */ c FROM test.reg_test_3427_1 WHERE id BETWEEN 1 AND 10 ORDER BY c",
 				0
 			},
 			{
-				"INSERT /* ;%s */ INTO test.reg_test_3427_0 (k) VALUES (2)",
+				"INSERT /*+ ;%s */ INTO test.reg_test_3427_0 (k) VALUES (2)",
 				0
 			},
 			{
-				"SELECT DISTINCT /* ;hostgroup=0;%s */ c FROM test.reg_test_3427_0 WHERE id BETWEEN 1 AND 10 ORDER BY c",
+				"SELECT DISTINCT /*+ ;hostgroup=0;%s */ c FROM test.reg_test_3427_0 WHERE id BETWEEN 1 AND 10 ORDER BY c",
 				0
 			},
 		}
@@ -148,31 +148,31 @@ std::vector<dst_hostgroup_test> dst_hostgroup_tests {
 		},
 		{
 			{
-				"UPDATE /* ;%s */ test.reg_test_3427_0 SET pad=\"random\" WHERE id=2",
+				"UPDATE /*+ ;%s */ test.reg_test_3427_0 SET pad=\"random\" WHERE id=2",
 				0
 			},
 			{
-				"SELECT /* ;hostgroup=0;%s */ c FROM test.reg_test_3427_0 WHERE id=1",
+				"SELECT /*+ ;hostgroup=0;%s */ c FROM test.reg_test_3427_0 WHERE id=1",
 				0
 			},
 			{
-				"SELECT /* ;hostgroup=0;%s */ c FROM test.reg_test_3427_0 WHERE id BETWEEN 1 AND 20",
+				"SELECT /*+ ;hostgroup=0;%s */ c FROM test.reg_test_3427_0 WHERE id BETWEEN 1 AND 20",
 				0
 			},
 			{
-				"SELECT /* ;hostgroup=0;%s */ SUM(k) c FROM test.reg_test_3427_0 WHERE id BETWEEN 1 AND 10",
+				"SELECT /*+ ;hostgroup=0;%s */ SUM(k) c FROM test.reg_test_3427_0 WHERE id BETWEEN 1 AND 10",
 				0
 			},
 			{
-				"SELECT /* ;%s */ c FROM test.reg_test_3427_0 WHERE id=1",
+				"SELECT /*+ ;%s */ c FROM test.reg_test_3427_0 WHERE id=1",
 				1
 			},
 			{
-				"SELECT /* ;%s */ c FROM test.reg_test_3427_0 WHERE id BETWEEN 1 AND 20",
+				"SELECT /*+ ;%s */ c FROM test.reg_test_3427_0 WHERE id BETWEEN 1 AND 20",
 				1
 			},
 			{
-				"SELECT /* ;%s */ SUM(k) c FROM test.reg_test_3427_0 WHERE id BETWEEN 1 AND 10",
+				"SELECT /*+ ;%s */ SUM(k) c FROM test.reg_test_3427_0 WHERE id BETWEEN 1 AND 10",
 				1
 			}
 		}
@@ -312,6 +312,100 @@ int create_testing_tables(MYSQL* proxysql, uint32_t num_tables) {
 	return EXIT_SUCCESS;
 }
 
+const double COLISSION_PROB = 1e-8;
+
+/**
+ * @brief Helper function to wait for replication to complete, 
+ *   performs a simple supplied queried until it succeed or the
+ *   timeout expires.
+ *
+ * @param proxysql A already opened MYSQL connection to ProxySQL.
+ * @param proxysql_admin A already opened MYSQL connection to ProxySQL Admin interface.
+ * @param check The query to perform until timeout expires.
+ * @param timeout The timeout in seconds to retry the query.
+ * @param reader_hostgroup The current 'reader hostgroup' for which
+ *   servers replication needs to be waited.
+ *
+ * @return EXIT_SUCCESS in case of success, EXIT_FAILURE
+ *   otherwise.
+ */
+int wait_for_replication(
+	MYSQL* proxysql,
+	MYSQL* proxysql_admin,
+	const std::string& check,
+	uint32_t timeout,
+	uint32_t read_hostgroup
+) {
+	if (proxysql == NULL) { return EXIT_FAILURE; }
+
+	const std::string t_count_reader_hg_servers {
+		"SELECT COUNT(*) FROM mysql_servers WHERE hostgroup_id=%d"
+	};
+	std::string count_reader_hg_servers {};
+	size_t size =
+		snprintf(
+			nullptr, 0, t_count_reader_hg_servers.c_str(), read_hostgroup
+		) + 1;
+	{
+		std::unique_ptr<char[]> buf(new char[size]);
+		snprintf(buf.get(), size, t_count_reader_hg_servers.c_str(), read_hostgroup);
+		count_reader_hg_servers = std::string(buf.get(), buf.get() + size - 1);
+	}
+
+	MYSQL_QUERY(proxysql_admin, count_reader_hg_servers.c_str());
+	MYSQL_RES* hg_count_res = mysql_store_result(proxysql_admin);
+	MYSQL_ROW row = mysql_fetch_row(hg_count_res);
+	uint32_t srv_count = strtoul(row[0], NULL, 10);
+	mysql_free_result(hg_count_res);
+
+	if (srv_count > UINT_MAX) {
+		return EXIT_FAILURE;
+	}
+
+	int waited = 0;
+	int queries = 0;
+	int result = EXIT_FAILURE;
+
+	if (srv_count != 0) {
+		int retries =
+			ceil(
+				log10(COLISSION_PROB) /
+				log10(static_cast<long double>(1)/srv_count)
+			);
+		auto start = std::chrono::system_clock::now();
+		std::chrono::duration<double> elapsed {};
+
+		while (elapsed.count() < timeout && queries < retries) {
+			int rc = mysql_query(proxysql, check.c_str());
+
+			if (rc == EXIT_SUCCESS) {
+				MYSQL_RES* st_res = mysql_store_result(proxysql);
+				if (st_res) {
+					mysql_free_result(st_res);
+				}
+
+				queries += 1;
+				continue;
+			} else {
+				queries = 0;
+				waited += 1;
+				sleep(1);
+			}
+
+			auto it_end = std::chrono::system_clock::now();
+			elapsed = it_end - start;
+		}
+
+		if (queries == retries) {
+			result = EXIT_SUCCESS;
+		}
+	} else {
+		result = EXIT_SUCCESS;
+	}
+
+	return result;
+}
+
 int main(int argc, char** argv) {
 	CommandLine cl;
 
@@ -348,10 +442,13 @@ int main(int argc, char** argv) {
 	int c_table_res = create_testing_tables(proxysql_text, 2);
 	if (c_table_res) { return EXIT_FAILURE; }
 
-	const std::string rep_check_query {
-		"SELECT CASE WHEN (SELECT COUNT(*) FROM test.reg_test_3427_0 WHERE id=1) = 1 THEN 'TRUE' ELSE 'FALSE' END"
-	};
-	int rep_err = wait_for_replication(proxysql_text, proxysql_admin, rep_check_query, 10, 1);
+	int rep_err = wait_for_replication(
+		proxysql_text,
+		proxysql_admin,
+		"SELECT c FROM test.reg_test_3427_0 WHERE id=1",
+		10,
+		1
+	);
 	if (rep_err) {
 		fprintf(stderr,
 			"File %s, line %d, Error: %s\n",
diff --git a/test/tap/tests/test_set_collation-t.cpp b/test/tap/tests/test_set_collation-t.cpp
index 380ca05224..13beabd1c1 100644
--- a/test/tap/tests/test_set_collation-t.cpp
+++ b/test/tap/tests/test_set_collation-t.cpp
@@ -18,21 +18,6 @@
 #define N_ITERATION_2  2
 #define N_ITERATION_3  3
 
-/**
- * NOTE: This is a duplicate of 'proxysql_find_charset_collate' in 'MySQL_Variables.h'. Including
- * 'MySQL_Variables' is not a easy task due to its interdependeces with other ProxySQL modules.
- */
-MARIADB_CHARSET_INFO * proxysql_find_charset_collate(const char *collatename) {
-	MARIADB_CHARSET_INFO *c = (MARIADB_CHARSET_INFO *)mariadb_compiled_charsets;
-	do {
-		if (!strcasecmp(c->name, collatename)) {
-			return c;
-		}
-		++c;
-	} while (c[0].nr != 0);
-	return NULL;
-}
-
 /**
  * @brief Creates a different MYSQL connection for each supplied collation. Logs in case of a
  *  failure creating a connection.
@@ -102,7 +87,7 @@ int query_and_check_session_variables(MYSQL *mysql, std::string collation, int i
 	MYSQL_RES* proxy_res = nullptr;
 	std::string query = "";
 	if (new_connection)
-		query += "/* ;create_new_connection=1 */ ";
+		query += "/*+ ;create_new_connection=1 */ ";
 	query += "SELECT lower(variable_name), variable_value FROM performance_schema.session_variables WHERE";
 	query +=" Variable_name IN ('character_set_client', 'character_set_connection', 'character_set_results', 'collation_connection') ORDER BY Variable_name";
 
diff --git a/test/tap/tests/test_unshun_algorithm-t.cpp b/test/tap/tests/test_unshun_algorithm-t.cpp
deleted file mode 100644
index b5924b10a7..0000000000
--- a/test/tap/tests/test_unshun_algorithm-t.cpp
+++ /dev/null
@@ -1,350 +0,0 @@
-/**
- * @file test_unshun_algorithm-t.cpp
- * @brief This test verifies the implementation of the new introduced variable 'mysql-unshun_algorithm'.
- * @details Test performs the following checks:
- *   1. Check that the variable default values and get/set operations works as expected.
- *   2. Check that the 'PROXYSQL_SIMULATOR' command is working properly.
- *   2. Check that the old 'SHUNNING' and 'UNSHUNNING' behavior works as expected. For this, multiple
- *   3. Check that the new 'SHUNNING' and 'UNSHUNNING' behavior 'mysql-unshun_algorithm=1' works as expected.
- *
- *   In order to check that 'SHUNNING' and 'UNSHUNNING' behavior holds:
- *   1. 10 fake servers are placed alone in 10 different hostgroups.
- *   2. The same servers are also placed incrementally in 10 other different hostgroups holding one more
- *      search each time.
- *   3. All the servers are 'SHUNNED' using 'PROXYSQL_SIMULATOR' command.
- *   4. Each of the servers placed in the individual hostgroups is 'UNSHUNNED', checking the proper behavior
- *      related to the other servers depending on 'mysql-unshun_algorithm'.
- */
-
-#include <cstring>
-#include <unistd.h>
-#include <vector>
-#include <string>
-#include <stdio.h>
-
-#include <mysql.h>
-#include <mysql/mysqld_error.h>
-
-#include "proxysql_utils.h"
-#include "tap.h"
-#include "command_line.h"
-#include "utils.h"
-
-const uint32_t SHUN_RECOVERY_TIME = 1;
-const uint32_t VALID_RANGE = 1;
-const uint32_t SERVERS_COUNT = 10;
-
-using std::string;
-
-int shunn_server(MYSQL* proxysql_admin, uint32_t i, uint32_t j) {
-	std::string t_simulator_error_query { "PROXYSQL_SIMULATOR mysql_error %d 127.0.0.1:330%d 1234" };
-	std::string simulator_error_q_i {};
-	string_format(t_simulator_error_query, simulator_error_q_i, i, j);
-	MYSQL_QUERY(proxysql_admin, simulator_error_q_i.c_str());
-
-	return EXIT_SUCCESS;
-}
-
-int shunn_all_servers(MYSQL* proxysql_admin) {
-	for (uint32_t i = 0; i < SERVERS_COUNT; i++) {
-		shunn_server(proxysql_admin, i, i);
-
-		for (uint32_t j = 0; j <= i; j++) {
-			shunn_server(proxysql_admin, i + SERVERS_COUNT, j);
-		}
-	}
-
-	return EXIT_SUCCESS;
-}
-
-int wakup_target_server(MYSQL* proxysql_mysql, uint32_t i) {
-	std::string t_simple_do_query { "DO /* ;hostgroup=%d */ 1" };
-	std::string simple_do_query {};
-	string_format(t_simple_do_query, simple_do_query, i);
-
-	mysql_query(proxysql_mysql, simple_do_query.c_str());
-	sleep(SHUN_RECOVERY_TIME * 2);
-	mysql_query(proxysql_mysql, simple_do_query.c_str());
-
-	return EXIT_SUCCESS;
-}
-
-int server_status_checker(MYSQL* admin, const string& f_st, const string& n_st, uint32_t i) {
-	std::string t_server_status_query {
-		"SELECT status FROM runtime_mysql_servers WHERE port=330%d order by hostgroup_id"
-	};
-	std::string server_status_query {};
-	string_format(t_server_status_query, server_status_query, i);
-	MYSQL_QUERY(admin, server_status_query.c_str());
-
-	MYSQL_RES* status_res = mysql_store_result(admin);
-	bool unexp_row_value = false;
-
-	int num_rows = mysql_num_rows(status_res);
-	if (num_rows == 0) {
-		unexp_row_value = true;
-	} else {
-		uint32_t row_num = 0;
-		MYSQL_ROW row = nullptr;
-
-		while (( row = mysql_fetch_row(status_res) )) {
-			std::string status { row[0] };
-			diag("Status found for server '127.0.0.1:330%d' was '%s'", i, status.c_str());
-			if (row_num == 0) {
-				if (status != f_st) {
-					unexp_row_value = true;
-					break;
-				}
-			} else {
-				if (status != n_st) {
-					unexp_row_value = true;
-					break;
-				}
-			}
-			row_num++;
-		}
-	}
-
-	mysql_free_result(status_res);
-
-	return unexp_row_value;
-}
-
-int test_unshun_algorithm_variable(MYSQL* proxysql_admin) {
-	const auto get_current_unshun_algorithm_val = [](MYSQL* proxysql_admin) -> int32_t {
-		int32_t cur_unshun_value = -1;
-
-		int err = mysql_query(proxysql_admin, "SELECT * FROM global_variables WHERE variable_name='mysql-unshun_algorithm'");
-		if (err != EXIT_SUCCESS) {
-			diag(
-				"Query for retrieving value of 'mysql-unshun_algorithm' failed with error: (%d, %s)",
-				mysql_errno(proxysql_admin), mysql_error(proxysql_admin)
-			);
-			return cur_unshun_value;
-		}
-
-		MYSQL_RES* myres_unshun_var = mysql_store_result(proxysql_admin);
-		if (myres_unshun_var != nullptr) {
-			int num_rows = mysql_num_rows(myres_unshun_var);
-			MYSQL_ROW row = mysql_fetch_row(myres_unshun_var);
-
-			if (num_rows && row != nullptr) {
-				char* endptr = nullptr;
-				cur_unshun_value = strtol(row[1], &endptr, SERVERS_COUNT);
-			}
-		}
-		mysql_free_result(myres_unshun_var);
-
-		return cur_unshun_value;
-	};
-
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES FROM DISK");
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-	int32_t def_unshun_value = get_current_unshun_algorithm_val(proxysql_admin);
-	ok(def_unshun_value == 0, "Default 'mysql-unshun_algorithm' should be '0', actual: %d", def_unshun_value);
-
-	std::string t_set_unshun { "SET mysql-unshun_algorithm=%d" };
-
-	for (uint32_t i = 0; i <= VALID_RANGE; i++) {
-		std::string set_unshun {};
-		string_format(t_set_unshun, set_unshun, i);
-		MYSQL_QUERY(proxysql_admin, set_unshun.c_str());
-		MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-
-		int32_t cur_unshun_val = get_current_unshun_algorithm_val(proxysql_admin);
-		ok(cur_unshun_val == i, "Settings and getting 'mysql-unshun_algorithm' works for range value: %d", i);
-	}
-
-	{
-		std::string set_unshun {};
-		string_format(t_set_unshun, set_unshun, VALID_RANGE + 1);
-		MYSQL_QUERY(proxysql_admin, set_unshun.c_str());
-		MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-
-		int32_t cur_unshun_val = get_current_unshun_algorithm_val(proxysql_admin);
-		ok(
-			cur_unshun_val != VALID_RANGE + 1,
-			"Settings and getting 'mysql-unshun_algorithm' doesn't work fo invalid range value: %d",
-			VALID_RANGE + 1
-		);
-	}
-
-	return EXIT_SUCCESS;
-}
-
-int test_proxysql_simulator_error(MYSQL* proxysql_admin) {
-	MYSQL_QUERY(proxysql_admin, "DELETE FROM mysql_servers");
-	const std::string t_insert_server_query { "INSERT INTO mysql_servers (hostgroup_id,hostname,port) VALUES (%d,'127.0.0.1',330%d)" };
-
-	// Create ten initial servers not sharing hostgroup
-	for (uint32_t i = 0; i < SERVERS_COUNT; i++) {
-		std::string insert_server_query {};
-		string_format(t_insert_server_query, insert_server_query, i, i);
-		MYSQL_QUERY(proxysql_admin, insert_server_query.c_str());
-	}
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL SERVERS TO RUNTIME");
-
-	// Check that ALL the servers are in the expected 'ONLINE' state
-	for (uint32_t i = 0; i < SERVERS_COUNT; i++) {
-		int check_res = server_status_checker(proxysql_admin, "ONLINE", "ONLINE", i);
-		if (check_res != false) {
-			diag("Found server in a different state than 'ONLINE' 'test_proxysql_simulator_error' can't be performed");
-			return EXIT_FAILURE;
-		}
-	}
-
-	for (uint32_t i = 0; i < SERVERS_COUNT; i++) {
-		shunn_server(proxysql_admin, i, i);
-		int check_res = server_status_checker(proxysql_admin, "SHUNNED", "SHUNNED", i);
-		ok(check_res == false, "'PROXYSQL_SIMULATOR' should set the servers with errors to 'SHUNNED'");
-	}
-
-
-	// Check that 'PROXYSQL_SIMULATOR' command fails when the server specified isn't found
-	int shunn_err = shunn_server(proxysql_admin, 20, 20);
-	ok(shunn_err == 1, "SHUNNING operation should have failed for a non-existing server.");
-
-	return EXIT_SUCCESS;
-}
-
-int test_unshun_algorithm_behavior(MYSQL* proxysql_mysql, MYSQL* proxysql_admin) {
-	// Configure Admin variables with lower thresholds
-	MYSQL_QUERY(proxysql_admin, "SET mysql-shun_recovery_time_sec=1");
-	// NOTE: The following varible value is set here just as a reminder. This change isn't properly propagated
-	// to the 'error setting operation' since this is performed from 'ProxySQL_Admin' thread when
-	// 'PROXYSQL_SIMULATOR' command is received. Because of this, it's in 'PROXYSQL_SIMULATOR' command impl in
-	// 'ProxySQL_Admin' where this variable value is updated before setting the error.
-	MYSQL_QUERY(proxysql_admin, "SET mysql-shun_on_failures=5");
-	MYSQL_QUERY(proxysql_admin, "SET mysql-connect_retries_on_failure=0");
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-	// Cleanup the servers and create a good number of hostgroups
-	MYSQL_QUERY(proxysql_admin, "DELETE FROM mysql_servers");
-
-	const std::string t_insert_server_query { "INSERT INTO mysql_servers (hostgroup_id,hostname,port) VALUES (%d,'127.0.0.1',330%d)" };
-
-	// Create ten initial servers not sharing hostgroup
-	for (uint32_t i = 0; i < SERVERS_COUNT; i++) {
-		std::string insert_server_query {};
-		string_format(t_insert_server_query, insert_server_query, i, i);
-		MYSQL_QUERY(proxysql_admin, insert_server_query.c_str());
-	}
-
-	// Place the same servers incrementally in ten new hostgroups
-	for (uint32_t i = 0; i < SERVERS_COUNT; i++) {
-		for (uint32_t j = 0; j <= i; j++) {
-			std::string insert_server_query {};
-			string_format(t_insert_server_query, insert_server_query, i + SERVERS_COUNT, j);
-			MYSQL_QUERY(proxysql_admin, insert_server_query.c_str());
-		}
-	}
-
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL SERVERS TO RUNTIME");
-
-	{
-		MYSQL_QUERY(proxysql_admin, "SET mysql-unshun_algorithm=0");
-		MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-
-		int shunn_err = shunn_all_servers(proxysql_admin);
-		if (shunn_err) { return EXIT_FAILURE; }
-
-		for (uint32_t i = 0; i < SERVERS_COUNT; i++) {
-			wakup_target_server(proxysql_mysql, i);
-
-			// Check that only server from first hostgroup is 'SHUNNED'
-			bool unexp_row_value = server_status_checker(proxysql_admin, "ONLINE", "SHUNNED", i);
-			ok(unexp_row_value == false, "Server from first hg was set 'ONLINE' while others remained 'SHUNNED'");
-		}
-	}
-
-	{
-		MYSQL_QUERY(proxysql_admin, "SET mysql-unshun_algorithm=1");
-		MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-
-		int shunn_err = shunn_all_servers(proxysql_admin);
-		if (shunn_err) { return EXIT_FAILURE; }
-
-		for (uint32_t i = 0; i < SERVERS_COUNT; i++) {
-			wakup_target_server(proxysql_mysql, i);
-
-			bool unexp_row_value = server_status_checker(proxysql_admin, "ONLINE", "ONLINE", i);
-			ok(unexp_row_value == false, "Server from first hg was set 'ONLINE' while others remained 'ONLINE'");
-		}
-	}
-
-	{
-		MYSQL_QUERY(proxysql_admin, "SET mysql-unshun_algorithm=0");
-		MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-
-		int shunn_err = shunn_all_servers(proxysql_admin);
-		if (shunn_err) { return EXIT_FAILURE; }
-
-		for (uint32_t i = 0; i < SERVERS_COUNT; i++) {
-			wakup_target_server(proxysql_mysql, i);
-		}
-
-		MYSQL_QUERY(proxysql_admin, "SET mysql-unshun_algorithm=1");
-		MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-
-		for (uint32_t i = 0; i < SERVERS_COUNT; i++) {
-			wakup_target_server(proxysql_mysql, i);
-
-			bool unexp_row_value = server_status_checker(proxysql_admin, "ONLINE", "SHUNNED", i);
-			ok(unexp_row_value == false, "Server from first hg was set 'ONLINE' while others remained 'SHUNNED'");
-		}
-	}
-
-
-	return EXIT_SUCCESS;
-}
-int main(int argc, char** argv) {
-	CommandLine cl;
-
-	plan(
-		1 + (VALID_RANGE + 1) + 1 + // Variable tests
-		SERVERS_COUNT + 1 + // Simulator error tests
-		SERVERS_COUNT * 3 // Testing unshun_algorithm behavior
-	);
-
-	if (cl.getEnv()) {
-		diag("Failed to get the required environmental variables.");
-		return -1;
-	}
-
-	MYSQL* proxysql_mysql = mysql_init(NULL);
-	MYSQL* proxysql_admin = mysql_init(NULL);
-
-	if (!mysql_real_connect(proxysql_mysql, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) {
-		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_mysql));
-		return EXIT_FAILURE;
-	}
-	if (!mysql_real_connect(proxysql_admin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) {
-		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxysql_mysql));
-		return EXIT_FAILURE;
-	}
-
-	{
-		int unshun_var_err = test_unshun_algorithm_variable(proxysql_admin);
-		if (unshun_var_err == EXIT_FAILURE) { goto cleanup; }
-	}
-
-	// Disable Monitor for the following tests
-	MYSQL_QUERY(proxysql_admin, "SET mysql-monitor_enabled=0");
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME");
-
-	{
-		int simulator_err = test_proxysql_simulator_error(proxysql_admin);
-		if (simulator_err == EXIT_FAILURE) { goto cleanup; }
-	}
-
-	{
-		int unshun_algorithm_err = test_unshun_algorithm_behavior(proxysql_mysql, proxysql_admin);
-		if (unshun_algorithm_err == EXIT_FAILURE) { goto cleanup; }
-	}
-
-cleanup:
-
-	mysql_close(proxysql_admin);
-	mysql_close(proxysql_mysql);
-
-	return exit_status();
-}
diff --git a/test/tap/tests/test_unsupported_queries-t.cpp b/test/tap/tests/test_unsupported_queries-t.cpp
index fff49064fc..2c02045efe 100644
--- a/test/tap/tests/test_unsupported_queries-t.cpp
+++ b/test/tap/tests/test_unsupported_queries-t.cpp
@@ -284,7 +284,7 @@ void helper_test_load_data_local_infile(
 
 			// Check that the data has actually been loaded to the database
 			// NOTE: Specifically target 'hostgroup=0' to avoid replication lag.
-			int myerr = mysql_query(proxysql, "SELECT * /* ;hostgroup=0 */ FROM test.load_data_local");
+			int myerr = mysql_query(proxysql, "SELECT * /*+ ;hostgroup=0 */ FROM test.load_data_local");
 			if (myerr) {
 				diag(
 					"Query 'SELECT * FROM test.load_data_local' for table preparation failed"