Repository: sysown/proxysql (language: cpp)

Issue:
Display a warning message for problematic OpenSSL versions
In ProxySQL 3.0 we stopped using statically linked OpenSSL in favor of dynamically linked.
This also means that an outdated version of OpenSSL can considerably slowdown ProxySQL.
For example, in a CI run where OpenSSL 3.0.2 is installed, the test `test_cacert_load_and_verify_duration-t` fails with:
```
msg: not ok 1 - 2025-02-14 22:49:32.351206 - Total duration is '60871 ms' should be less than 20 Seconds
```

I think we need to take a series of actions:
* [ ] export via status variables what OpenSSL version is in use
* [ ] test `test_cacert_load_and_verify_duration-t` should check OpenSSL version using such variable, and adjust the time threshold
* [ ] When ProxySQL prints the OpenSSL version (ex: `[INFO] Using OpenSSL version: OpenSSL 3.0.2 15 Mar 2022`) it should also display a warning for problematic known OpenSSL versions


Note:
Maybe (not sure) issue #4828 is related to OpenSSL version too


Discussion / hints:

Fix patch:
diff --git a/lib/ProxySQL_Admin_Stats.cpp b/lib/ProxySQL_Admin_Stats.cpp
index c6b477f93..3e314a8c3 100644
--- a/lib/ProxySQL_Admin_Stats.cpp
+++ b/lib/ProxySQL_Admin_Stats.cpp
@@ -591,6 +591,7 @@ void ProxySQL_Admin::stats___mysql_global() {
 	}
 
 	sqlite3_global_stats_row_step(statsdb, row_stmt, "mysql_listener_paused", admin_proxysql_mysql_paused);
+	sqlite3_global_stats_row_step(statsdb, row_stmt, "OpenSSL_Version_Num", OpenSSL_version_num());
 
 	statsdb->execute("COMMIT");
 }
diff --git a/src/main.cpp b/src/main.cpp
index 7c1006c01..8f9ce9316 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -341,8 +341,15 @@ static void init_locks(void) {
 static bool check_openssl_version() {
 	unsigned long version = OpenSSL_version_num();
 	const unsigned long OPENSSL_3_0_0 = 0x30000000L;
+	const unsigned long OPENSSL_3_2_0 = 0x30200000L;
 
 	proxy_info("Using OpenSSL version: %s\n", OpenSSL_version(OPENSSL_VERSION));
+	if (version > OPENSSL_3_0_0 && version < OPENSSL_3_2_0) {
+		proxy_warning(
+			"Detected OpenSSL version has known performance regressions, please upgrade to '3.2.0' or later."
+			" For further details, please refer to: https://github.com/openssl/openssl/issues/18814\n"
+		);
+	}
 	if (version < OPENSSL_3_0_0) {
 		proxy_error("%s\n", "ProxySQL server required openssl version 3.0.0 or above");
 		return false;


Test patch:
diff --git a/test/tap/tap/utils.cpp b/test/tap/tap/utils.cpp
index 21061f4d0..79238b910 100644
--- a/test/tap/tap/utils.cpp
+++ b/test/tap/tap/utils.cpp
@@ -243,6 +243,22 @@ string to_string(std::thread::id id) {
 	return helper.str();
 }
 
+string replace_str(const string& str, const string& match, const string& repl) {
+	if(match.empty()) {
+		return str;
+	}
+
+	string result { str };
+	size_t start_pos = 0;
+
+	while((start_pos = result.find(match, start_pos)) != std::string::npos) {
+		result.replace(start_pos, match.length(), repl);
+		start_pos += repl.length();
+	}
+
+	return result;
+}
+
 pair<int,vector<MYSQL*>> disable_core_nodes_scheduler(CommandLine& cl, MYSQL* admin) {
 	vector<MYSQL*> nodes_conns {};
 
diff --git a/test/tap/tap/utils.h b/test/tap/tap/utils.h
index bb22de272..c2d19a517 100644
--- a/test/tap/tap/utils.h
+++ b/test/tap/tap/utils.h
@@ -21,6 +21,9 @@
 template <typename T>
 using rc_t = std::pair<int,T>;
 
+#define _S(s) ( std::string {s} )
+#define _TO_S(s) ( std::to_string(s) )
+
 // Improve dependency failure compilation error
 #ifndef DISABLE_WARNING_COUNT_LOGGING
 
@@ -63,6 +66,12 @@ my_bool mysql_stmt_close_override(MYSQL_STMT* stmt, const char* file, int line);
 
 #endif 
 
+/**
+ * @brief Simple macro to use with 'mysql_query' versions.
+ * @details E.g: `mysql_query_ext_val(admin, SELECT_RUNTIME_VAR"'mysql-eventslog_filename'", "")`.
+ */
+#define SELECT_RUNTIME_VAR "SELECT variable_value FROM runtime_global_variables WHERE variable_name="
+
 /**
  * @brief Computes the binomial coefficient C(n, k)
  */
@@ -95,6 +104,15 @@ int find_min_elems(double tg_prob, int M);
  */
 std::string to_string(std::thread::id id);
 
+/**
+ * @brief Replaces all occurrences of a substring in a given string with another substring.
+ * @param str The string which matches are to be replaced.
+ * @param match The string which occurrences shall be replaced.
+ * @param repl The string used to replace 'match' occurrences.
+ * @return A new string with all 'match' occurrences replaced by 'repl'.
+ */
+std::string replace_str(const std::string& str, const std::string& match, const std::string& repl);
+
 /**
  * @brief Helper function to disable Core nodes scheduler from ProxySQL Cluster nodes.
  * @details In the CI environment, 'Scheduler' is used to induce extra load via Admin interface on
@@ -221,6 +239,19 @@ enum SQ3_RES_T {
  */
 sq3_res_t sqlite3_execute_stmt(sqlite3* db, const std::string& query);
 
+/**
+ * @brief Utility one-liner macro to check for query failure on a 'ext_val_t<T>'.
+ * @param val The 'ext_val_t<T>' to be checked.
+ * @return In case of failure, 'EXIT_FAILURE' after logging the error, continues otherwise.
+ */
+#define CHECK_EXT_VAL(val)\
+	do {\
+		if (val.err) {\
+			diag("%s:%d: Query failed   err=\"%s\"", __func__, __LINE__, val.str.c_str());\
+			return EXIT_FAILURE;\
+		}\
+	} while(0)
+
 /**
  * @brief Holds the result of an `mysql_query_ext_val` operation.
  */
diff --git a/test/tap/tests/generate_set_session_csv.cpp b/test/tap/tests/generate_set_session_csv.cpp
index 7829d4edb..b9e91b03c 100644
--- a/test/tap/tests/generate_set_session_csv.cpp
+++ b/test/tap/tests/generate_set_session_csv.cpp
@@ -19,6 +19,11 @@ std::vector<int> int_values = {
 	10, 20, 100, 1010, 1234, 3456, 7890, 34564, 68100, 123456, 456123
 };
 
+std::vector<int> mariadb_compatible_tmp_table_size = {
+	32768, 49152, 65536, 81920, 98304, 114688, 131072, 131072, 147456, 163840, 180224,
+	196608, 212992, 229376, 245760, 262144, 491520, 507904, 524288, 540672, 557056
+};
+
 std::vector<int> int_values_small = {
 	13, 32, 110, 310, 434, 558, 789
 };
@@ -188,8 +193,20 @@ int main() {
 	vars["max_join_size"]->add("18446744073709551615");
 	vars["max_join_size"]->add("DEFAULT");
 	vars["tmp_table_size"] = std::make_unique<variable>("tmp_table_size", true, true, false);
-	vars["tmp_table_size"]->add(int_values, 10050);
-	vars["tmp_table_size"]->add("18446744000000051615");
+	// NOTE: Since recent MariaDB versions (known affected version 10.11.11), values which are not multiples
+	// of '16384' for 'tmp_table_size' generate truncate warnings:
+	//  - Warning for max value:
+	//    +---------+------+--------------------------------------------------------+
+	//    | Level   | Code | Message                                                |
+	//    +---------+------+--------------------------------------------------------+
+	//    | Warning | 1292 | Truncated incorrect tmp_table_size value: '4294967295' |
+	//    +---------+------+--------------------------------------------------------+
+	//  - https://github.com/MariaDB/server/blob/31adb3030ce531009457913cbf947456ad606646/sql/sys_vars.cc#L4486
+	// The value woule be set to the nearest valid block_size, this is also true for the maximum value.
+	// Warnings, in combination with 'sql_mode=TRADITIONAL' will trigger errors, preventing the test to run
+	// for recent MariaDB versions.
+	vars["tmp_table_size"]->add(mariadb_compatible_tmp_table_size, 16384);
+	vars["tmp_table_size"]->add("4294950912");
 	vars["max_heap_table_size"] = std::make_unique<variable>("max_heap_table_size", true, true, false);
 	vars["max_heap_table_size"]->add(int_values, 20031);
 	vars["max_heap_table_size"]->add("8446744073709547520");
diff --git a/test/tap/tests/mysql-protocol_compression_level-t.cpp b/test/tap/tests/mysql-protocol_compression_level-t.cpp
index b01565cb7..354d11744 100644
--- a/test/tap/tests/mysql-protocol_compression_level-t.cpp
+++ b/test/tap/tests/mysql-protocol_compression_level-t.cpp
@@ -1,261 +1,344 @@
+/**
+ * @file mysql-protocol_compression_level-t.cpp
+ * @brief Checks 'mysql-protocol_compression_level' variable and its performance impact.
+ * @details The test generates an artificially large resultset from a simple, small test table. Cross-joins of
+ *  this table are used to generate bigger resulsets. The column selection is generated randomly in a
+ *  per-query based to prevent forms of caching/exact memory patterns on server side. In it's current form the
+ *  test uses '20', '40Mb' randomly generated packets, measuring the average overhead per-packet that is
+ *  imposed when different compression levels are enabled. A slight delay is imposed between each packet
+ *  fetch, preventing to fetch more than '10' packets per-second. This is done to completely isolate the load
+ *  and attempting to prevent any form of network saturation.
+ */
+
+#include <cmath>
 #include <cstdlib>
 #include <cstdio>
 #include <cstring>
 #include <unistd.h>
 
+#include <random>
 #include <string>
-#include <sstream>
-#include <fstream>
+#include <vector>
+
 #include "mysql.h"
+#include "json.hpp"
 
 #include "tap.h"
 #include "command_line.h"
 #include "utils.h"
 
-unsigned long calculate_query_execution_time(MYSQL* mysql, const std::string& query) {
-	MYSQL_RES *res;
-	MYSQL_ROW row;
-	unsigned long long begin = monotonic_time();
-	unsigned long long row_count = 0;
-	unsigned long ret_query = 0;
-
-	ret_query = mysql_query(mysql, query.c_str());
-	if (ret_query != 0) {
-		fprintf(stderr, "Failed to execute query: Error: %s\n", mysql_error(mysql));
-		return -1;
-	}
+using std::string;
+using std::vector;
 
-	res = mysql_use_result(mysql);
-	unsigned long long num_rows = mysql_num_rows(res);
-	unsigned int num_fields = mysql_num_fields(res);
-	while ((row = mysql_fetch_row(res))) {
-		for (unsigned int i = 1; i < num_fields; i++) {
-			char *field = row[i];
-		}
-		row_count++;
-	}
-	mysql_free_result(res);	
-	unsigned long long end = monotonic_time();
-	fprintf(stderr, "Row count: %lld\n", row_count);
-	return (end - begin);
-}
+std::random_device rd;
+std::mt19937 gen(rd());
 
-MYSQL* initilize_mysql_connection(char* host, char* username, char* password, int port, bool compression) {
-	MYSQL* mysql = mysql_init(NULL);
-	if (!mysql)
-		return nullptr;
+string get_rnd_fields(const vector<string>& fields) {
+	vector<string> _fields { fields };
+	std::shuffle(_fields.begin(), _fields.end(), gen);
+	const string fields_str { join(", ", _fields) };
 
-	fprintf(stderr, "MySQL connection details: %s %s %d\n", username, password, port);
-	if (compression) {
-		if (mysql_options(mysql, MYSQL_OPT_COMPRESS, nullptr) != 0) {
-			fprintf(stderr, "Failed to set mysql compression option: Error: %s\n",
-					mysql_error(mysql));
-			return nullptr;
-		}
-	}
-	if (!mysql_real_connect(mysql, host, username, password, NULL, port, NULL, 0)) {
-	    fprintf(stderr, "Failed to connect to database: Error: %s\n",
-	              mysql_error(mysql));
-		return nullptr;
-	}
-	return mysql;
+	return fields_str;
 }
 
-int main(int argc, char** argv) {
+uint64_t measure_avg_query_time(
+	MYSQL* mysql, const string& q, const vector<string>& fields, uint32_t its=10
+) {
+	diag(
+		"Starting query measurement   q=\"%s\" fields=\"%s\" its=%d",
+		q.c_str(), nlohmann::json(fields).dump().c_str(), its
+	);
 
-	CommandLine cl;
-	std::string query = "SELECT t1.id id1, t1.k k1, t1.c c1, t1.pad pad1, t2.id id2, t2.k k2, t2.c c2, t2.pad pad2 FROM test.sbtest1 t1 JOIN test.sbtest1 t2 LIMIT 90000000";
-	unsigned long time_proxy = 0;
-	unsigned long time_proxy_compression_level_default = 0;
-	unsigned long time_proxy_compression_level_8 = 0;	
-	long diff = 0;
-	unsigned long time_mysql_compressed = 0;
-	unsigned long time_mysql_without_compressed = 0;
-	std::string compression_level = {""};
-	int32_t ret = 0;
-	MYSQL* proxysql = nullptr;
-	MYSQL* proxysql_compression = nullptr;
-	MYSQL* proxysql_admin = nullptr;
-	MYSQL* mysql_compression = nullptr;
-	MYSQL* mysql = nullptr;
-	float performance_diff = 0;
-
-	if(cl.getEnv())
-		return exit_status();
-
-	plan(9);
-
-	// ProxySQL connection without compression
-	proxysql = initilize_mysql_connection(cl.host, cl.username, cl.password, cl.port, false);
-	if (!proxysql) {
-		goto cleanup;
-	}
+	uint64_t avg { 0 };
+	uint64_t row_count { 0 };
+	uint64_t delay_us = std::pow(10, 6) / its;
 
-	// ProxySQL connection with compression
-	proxysql_compression = initilize_mysql_connection(cl.host, cl.username, cl.password, cl.port, true);
-	if (!proxysql_compression) {
-		goto cleanup;
-	}
+	for (uint32_t i = 0; i < its; i++) {
+		const string it_fields { get_rnd_fields(fields) };
+		const string it_query { replace_str(q, "?", it_fields) };
 
-	// MySQL connection without compression
-	mysql = initilize_mysql_connection(cl.host, cl.username, cl.password, cl.mysql_port, false);
-	if (!mysql) {
-		goto cleanup;
-	}
+		diag(" :: Starting it query measurement   it_fields=\"%s\" it=%d", it_fields.c_str(), i);
 
-	// MySQL connection with compression
-	mysql_compression = initilize_mysql_connection(cl.host, cl.username, cl.password, cl.mysql_port, true);
-	if (!mysql_compression) {
-		goto cleanup;
-	}
+		unsigned long long begin = monotonic_time();
 
-	// ProxySQL admin connection
-	proxysql_admin = initilize_mysql_connection(cl.host, cl.admin_username, cl.admin_password, cl.admin_port, false);
-	if (!proxysql_admin) {
-		goto cleanup;
-	}
+		MYSQL_QUERY(mysql, it_query.c_str());
 
-	// Change default query rules to avoid replication issues; This test only requires the default hostgroup
-	MYSQL_QUERY(proxysql_admin, "UPDATE mysql_query_rules SET active=0");
-	MYSQL_QUERY(proxysql_admin, "LOAD MYSQL QUERY RULES TO RUNTIME");
+		MYSQL_RES* res = mysql_use_result(mysql);
+		while (MYSQL_ROW row = mysql_fetch_row(res)) {
+			row_count += 1;
+		}
 
-	MYSQL_QUERY(proxysql, "CREATE DATABASE IF NOT EXISTS test");
-	MYSQL_QUERY(proxysql, "DROP TABLE IF EXISTS test.sbtest1");
+		// NOTE: This is an interesting case. Fetching the resulset at once, appears to be slightly slower
+		// than doing it row by row. This can be interesting to investigate (check non-debug build).
+		// MYSQL_RES* res = mysql_store_result(mysql);
+		// row_count += mysql_num_rows(res);
 
-	mysql_query(proxysql, "CREATE TABLE IF NOT EXISTS test.sbtest1 (id INT UNSIGNED NOT NULL AUTO_INCREMENT, k INT 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_free_result(res);
+		unsigned long long end = monotonic_time();
 
-	MYSQL_QUERY(proxysql, "USE test");
+		avg += (end - begin);
 
-	for (int i = 0; i < 100; i++) {
-		MYSQL_QUERY(proxysql, "INSERT INTO sbtest1 (k, c, pad) SELECT FLOOR(RAND() * 10000), REPEAT('a', 120), REPEAT('b', 60) FROM information_schema.tables LIMIT 1000;");
+		usleep(delay_us);
 	}
 
-	time_proxy = calculate_query_execution_time(proxysql, query);
-	diag("Time taken for query with proxysql without compression: %ld", time_proxy);
-	if (time_proxy == -1) {
-		goto cleanup;
-	}
+	diag("Finished query measurement   q=\"%s\" its=%d rows=%lu", q.c_str(), its, row_count);
 
-	time_proxy_compression_level_default = calculate_query_execution_time(proxysql_compression, query);
-	diag("Time taken for query with proxysql with default compression (3): %ld", time_proxy_compression_level_default);
-	if (time_proxy_compression_level_default == -1) {
-		goto cleanup;
-	}
+	avg /= its;
+
+	return avg;
+}
 
-	diff = time_proxy_compression_level_default - time_proxy;
-	performance_diff = (float)(diff * 100) / time_proxy;
+MYSQL* init_mysql_conn(char* host, char* user, char* pass, int port, bool cmp=false) {
+	diag("Creating MySQL conn   host=\"%s\" port=\"%d\" cmp=\"%d\"", user, port, cmp);
 
-	ok((performance_diff > 0), "proxysql without compression performed well compared to default compression level (3). Performance difference: %f percentage", performance_diff);
+	MYSQL* mysql = mysql_init(NULL);
 
-	time_mysql_without_compressed = calculate_query_execution_time(mysql, query);
-	diag("Time taken for query with mysql without compression: %ld", time_mysql_without_compressed);
-	if (time_mysql_without_compressed == -1) {
-		goto cleanup;
+	if (!mysql) {
+		return nullptr;
 	}
+	if (cmp) {
+		if (mysql_options(mysql, MYSQL_OPT_COMPRESS, nullptr)) {
+			return nullptr;
+		}
+	}
+	if (!mysql_real_connect(mysql, host, user, pass, NULL, port, NULL, 0)) {
+		return nullptr;
+	}
+
+	return mysql;
+}
 
-	time_mysql_compressed = calculate_query_execution_time(mysql_compression, query);
-	diag("Time taken for query with mysql with compression: %ld", time_mysql_compressed);
-	if (time_mysql_compressed == -1) {
-		goto cleanup;
+const char version_comment_query[] { "select @@version_comment limit 1" };
+
+int check_perf_diff(const string tcase, double time1, double time2, double exp_diff, bool _diag=false) {
+	double diff = time2 - time1;
+	double perf_diff = double(diff * 100) / time1;
+
+	if (_diag) {
+		diag(
+			"For diagnosing: Computed perf diff   case=\"%s\" perf_diff=%lf",
+			tcase.c_str(), perf_diff
+		);
+	} else {
+		ok(
+			exp_diff > 0 ? perf_diff < exp_diff : perf_diff > (-exp_diff),
+			"Perf diff within expected range   case=\"%s\" perf_diff=%lf exp_diff=%lf",
+			tcase.c_str(), perf_diff, std::abs(exp_diff)
+		);
 	}
 
-	diff = time_mysql_compressed - time_mysql_without_compressed;
-	performance_diff = (float)(diff * 100) / time_mysql_without_compressed;
+	return EXIT_SUCCESS;
+}
+
+int main(int argc, char** argv) {
+	plan(8);
 
-	ok((performance_diff > 0), "MySQL without compression performed well compared to mysql with compression. Performance difference: %f percentage", performance_diff);
+	CommandLine cl;
 
-	ret = get_variable_value(proxysql_admin, "mysql-protocol_compression_level", compression_level, true);
-	if (ret == EXIT_SUCCESS) {
-		ok(compression_level == "3", "Run-time default compression level is correct: %s", compression_level.c_str());
-	}
-	else {
-		diag("Failed to get the default compression level.");
-		goto cleanup;
+	if (cl.getEnv()) {
+		diag("Failed to get the required environmental variables.");
+		return EXIT_FAILURE;
 	}
 
-	ret = get_variable_value(proxysql_admin, "mysql-protocol_compression_level", compression_level);
-	if (ret == EXIT_SUCCESS) {
-		ok(compression_level == "3", "Default compression level is correct: %s", compression_level.c_str());
+	MYSQL* admin = init_mysql_conn(cl.host, cl.admin_username, cl.admin_password, cl.admin_port);
+	if (!admin) {
+		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(admin));
+		return EXIT_FAILURE;
 	}
-	else {
-		diag("Failed to get the default compression level.");
-		goto cleanup;
+
+	MYSQL* proxy = init_mysql_conn(cl.host, cl.username, cl.password, cl.port);
+	if (!proxy) {
+		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(admin));
+		return EXIT_FAILURE;
 	}
 
-	set_admin_global_variable(proxysql_admin, "mysql-protocol_compression_level", "8");
-	if (mysql_query(proxysql_admin, "load mysql variables to runtime")) {
-		diag("Failed to load mysql variables to runtime.");
-		goto cleanup;
+	// Disable query rules to avoid replication issues; Test uses default hostgroup
+	MYSQL_QUERY_T(admin, "UPDATE mysql_query_rules SET active=0");
+	MYSQL_QUERY_T(admin, "LOAD MYSQL QUERY RULES TO RUNTIME");
+
+	MYSQL_QUERY_T(proxy, "CREATE DATABASE IF NOT EXISTS test");
+	MYSQL_QUERY_T(proxy, "DROP TABLE IF EXISTS test.sbtest1");
+
+	MYSQL_QUERY_T(proxy,
+		"CREATE TABLE IF NOT EXISTS test.sbtest1 ("
+			" id INT UNSIGNED NOT NULL AUTO_INCREMENT,"
+			" k INT UNSIGNED NOT NULL DEFAULT 0,"
+			" c CHAR(112) NOT NULL DEFAULT '',"
+			" pad CHAR(80) NOT NULL DEFAULT '',"
+			" PRIMARY KEY (id), KEY k_1 (k)"
+		" )"
+	);
+
+	MYSQL_QUERY_T(proxy, "USE test");
+
+	// Generate '256' entries: (4 + 4 + 112 + 80) * 256 ~= 51.2kb
+	MYSQL_QUERY_T(proxy,
+		"INSERT INTO sbtest1 (`k`, `c`, `pad`)"
+		" SELECT"
+			" FLOOR(RAND() * 1000) AS `k`,"
+			" LEFT(REPEAT(MD5(RAND()), 4), 112) AS `c`,"
+			" LEFT(REPEAT(MD5(RAND()), 3), 80) AS `pad`"
+		" FROM"
+			" (SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4) as u1,"
+			" (SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4) as u2,"
+			" (SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4) as u3,"
+			" (SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4) as u4;"
+	);
+
+	MYSQL* proxy_cmp = init_mysql_conn(cl.host, cl.username, cl.password, cl.port, true);
+	if (!proxy_cmp) {
+		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxy_cmp));
+		return EXIT_FAILURE;
 	}
-	ret = get_variable_value(proxysql_admin, "mysql-protocol_compression_level", compression_level, true);
-	if (ret == EXIT_SUCCESS) {
-		ok(compression_level == "8", "Run-time Compression level is set correctly: %s", compression_level.c_str());
+	MYSQL* mysql = init_mysql_conn(cl.host, cl.username, cl.password, cl.mysql_port, false);
+	if (!mysql) {
+		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(mysql));
+		return EXIT_FAILURE;
 	}
-	else {
-		diag("Failed to set the Compression level is set correctly:");
-		goto cleanup;
+	MYSQL* mysql_cmp = init_mysql_conn(cl.host, cl.username, cl.password, cl.mysql_port, true);
+	if (!mysql_cmp) {
+		fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(mysql_cmp));
+		return EXIT_FAILURE;
 	}
 
-	ret = get_variable_value(proxysql_admin, "mysql-protocol_compression_level", compression_level);
-	if (ret == EXIT_SUCCESS) {
-		ok(compression_level == "8", "Compression level is set correctly: %s", compression_level.c_str());
-	}
-	else {
-		diag("Failed to set the Compression level is set correctly:");
-		goto cleanup;
+	const vector<string> fields {
+		"t1.id id1", "t1.k k1", "t1.c c1", "t1.pad pad1", "t1.id id2", "t1.k k2", "t1.c c2", "t1.pad pad2"
+	};
+
+	// Generates rows doubling the original columns (51.2kb * 2 =~ 102.4kb). Then it multiplies the number of
+	// rows using cross-joins (102kb * (100 * 4) ~= 40800mb). Each resulset is expected to have around 40mb.
+	const char select_query[] {
+		"SELECT"
+			" ?" // " t1.id id1, t1.k k1, t1.c c1, t1.pad pad1, t1.id id2, t1.k k2, t1.c c2, t1.pad pad2"
+		" FROM"
+			" test.sbtest1 t1"
+			" CROSS JOIN ("
+				" SELECT a.n + (b.n - 1) * 10 AS num"
+				" FROM ("
+					" SELECT 1 AS n UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL"
+					" SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL"
+					" SELECT 9 UNION ALL SELECT 10"
+				" ) a"
+				" CROSS JOIN ("
+					" SELECT 1 AS n UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL"
+					" SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL"
+					" SELECT 9 UNION ALL SELECT 10"
+				" ) b" // 10MB
+				" CROSS JOIN ("
+					" SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4"
+				") c" // 40MB
+			" ) num"
+	};
+
+	diag("Meassuring ProxySQL time *WITHOUT* compression");
+	uint64_t proxy_time = measure_avg_query_time(proxy, select_query, fields, 20);
+	if (proxy_time == 0) { return EXIT_FAILURE; }
+
+	diag("Meassuring ProxySQL time *WITH* compression   cmp_lvl=3");
+	MYSQL_QUERY_T(admin, "SET mysql-protocol_compression_level=3");
+	MYSQL_QUERY_T(admin, "LOAD MYSQL VARIABLES TO RUNTIME");
+
+	{
+		string cmp_lvl {};
+		int rc = get_variable_value(admin, "mysql-protocol_compression_level", cmp_lvl, true);
+		if (rc) { return EXIT_FAILURE; }
+		ok(cmp_lvl == "3", "Runtime Compression level set correctly: %s", cmp_lvl.c_str());
+		rc = get_variable_value(admin, "mysql-protocol_compression_level", cmp_lvl);
+		if (rc) { return EXIT_FAILURE; }
+		ok(cmp_lvl == "3", "Compression level set correctly: %s", cmp_lvl.c_str());
 	}
 
-	time_proxy_compression_level_8 = calculate_query_execution_time(proxysql_compression, query);
-	diag("Time taken for query with proxysql with compression level 8: %ld", time_proxy_compression_level_8);
-	if (time_proxy_compression_level_8 == -1) {
-		goto cleanup;
+	uint64_t proxy_cmp_time = measure_avg_query_time(proxy_cmp, select_query, fields, 20);
+	if (proxy_cmp_time == 0) { return EXIT_FAILURE; }
+
+	diag("Meassuring ProxySQL time *WITH* compression   cmp_lvl=8");
+	MYSQL_QUERY_T(admin, "SET mysql-protocol_compression_level=8");
+	MYSQL_QUERY_T(admin, "LOAD MYSQL VARIABLES TO RUNTIME");
+
+	{
+		string cmp_lvl {};
+		int rc = get_variable_value(admin, "mysql-protocol_compression_level", cmp_lvl, true);
+		if (rc) { return EXIT_FAILURE; }
+		ok(cmp_lvl == "8", "Runtime Compression level is set correctly: %s", cmp_lvl.c_str());
+		rc = get_variable_value(admin, "mysql-protocol_compression_level", cmp_lvl);
+		if (rc) { return EXIT_FAILURE; }
+		ok(cmp_lvl == "8", "Compression level is set correctly: %s", cmp_lvl.c_str());
 	}
 
-	diff = time_proxy_compression_level_8 - time_proxy_compression_level_default;
-	performance_diff = (float)(diff * 100) / time_proxy_compression_level_default;
+	uint64_t proxy_cmp8_time = measure_avg_query_time(proxy_cmp, select_query, fields, 20);
+	if (proxy_cmp8_time == 0) { return EXIT_FAILURE; }
+
+	diag("Meassuring MySQL time *WITHOUT* compression");
+	uint64_t mysql_time = measure_avg_query_time(mysql, select_query, fields, 20);
+	if (proxy_time == 0) { return EXIT_FAILURE; }
+
+	diag("Meassuring MySQL time *WITH* compression");
+	uint64_t mysql_cmp_time = measure_avg_query_time(mysql_cmp, select_query, fields, 20);
+	if (mysql_cmp_time == 0) { return EXIT_FAILURE; }
+
+	diag(
+		"Avg ProxySQL query time   proxy=%lu proxy_cmp_3=%lu proxy_cmp_8=%lu mysql=%lu mysql_cmp=%lu",
+		proxy_time, proxy_cmp_time, proxy_cmp8_time, mysql_time, mysql_cmp_time
+	);
+
+	// COHERENCE CHECKS
+	// ////////////////////////////////////////////////////////////////////////
+	// proxy < proxy_cmp(3): Normally this value goes below '200%'. When the value goes above that threshold,
+	// isn't because the compressed workload is slower than in other runs, but because the non-compressed load
+	// slightly faster than usual. No further investigation have gone into this.
+	int rc = check_perf_diff("proxysql-proxysql_cmp(3)", proxy_time, proxy_cmp_time, 350);
+	if (rc) { return EXIT_FAILURE; }
+
+	// proxy < proxy_cmp(8): Normally this diff goes below '500%'. See comment for 'proxysql-proxysql_cmp(3)'.
+	rc = check_perf_diff("proxysql-proxysql_cmp(8)", proxy_time, proxy_cmp8_time, 650);
+	if (rc) { return EXIT_FAILURE; }
+
+	// proxy_cmp(3) < proxy_cmp(8)
+	rc = check_perf_diff("proxysql_cmp(3)-proxysql_cmp(8)", proxy_cmp_time, proxy_cmp8_time, 250);
+	if (rc) { return EXIT_FAILURE; }
+
+	// mysql < mysql_cmp: Normally this sits between 305-350. Since this measurement in isolation is the least
+	// interesting to us, we give it a bigger threshold.
+	rc = check_perf_diff("mysql-mysql_cmp", mysql_time, mysql_cmp_time, 550);
+	if (rc) { return EXIT_FAILURE; }
+
+	// MYSQL PERF COMPARISONS
+	// ////////////////////////////////////////////////////////////////////////
+	// proxy < mysql_cmp: Local tests show ProxySQL having at least a '200%' perf diff to MySQL. This
+	// measurements can't be reproduced on the CI, as the base 'proxy_time' is slower. The diff is left for
+	// further diagnosing.
+	rc = check_perf_diff("proxysql-mysql_cmp", proxy_time, mysql_cmp_time, -150, true);
+
+	// proxy_cmp < mysql_cmp: Local tests show ProxySQL having at least a '60%' perf diff to MySQL. This
+	// measurements can't be reproduced on the CI, as the base 'proxy_time' is slower. But the diff is left
+	// for further diagnosing.
+	rc = check_perf_diff("proxysql_cmp-mysql_cmp", proxy_cmp_time, mysql_cmp_time, -5, true);
+	if (rc) { return EXIT_FAILURE; }
 
-	ok((performance_diff > 0), "proxysql with default compression level (3) performed well compared to compression level (8). Performance difference: %f percentage", performance_diff);
+	// Recover default query rules
+	if (admin) {
+		MYSQL_QUERY_T(admin, "UPDATE mysql_query_rules SET active=1");
+		MYSQL_QUERY_T(admin, "LOAD MYSQL QUERY RULES TO RUNTIME");
 
-	set_admin_global_variable(proxysql_admin, "mysql-protocol_compression_level", "3");
-	if (mysql_query(proxysql_admin, "load mysql variables to runtime")) {
-		diag("Failed to load mysql variables to runtime.");
-		goto cleanup;
-	}	
-	ret = get_variable_value(proxysql_admin, "mysql-protocol_compression_level", compression_level, true);
-	if (ret == EXIT_SUCCESS) {
-		ok(compression_level == "3", "Run-time Compression level set correctly: %s", compression_level.c_str());
-	}
-	else {
-		diag("Failed to set the Compression level set correctly:");
-		goto cleanup;
+		MYSQL_QUERY_T(admin, "SET mysql-protocol_compression_level=3");
+		MYSQL_QUERY_T(admin, "LOAD MYSQL VARIABLES TO RUNTIME");
 	}
 
-	ret = get_variable_value(proxysql_admin, "mysql-protocol_compression_level", compression_level);
-	if (ret == EXIT_SUCCESS) {
-		ok(compression_level == "3", "Compression level set correctly: %s", compression_level.c_str());
+	if (proxy) {
+		mysql_close(proxy);
 	}
-	else {
-		diag("Failed to set the Compression level set correctly:");
-		goto cleanup;
+	if (proxy_cmp) {
+		mysql_close(proxy_cmp);
 	}
-
-cleanup:
-	// Recover default query rules
-	if (proxysql_admin) {
-		MYSQL_QUERY(proxysql_admin, "UPDATE mysql_query_rules SET active=1");
-		MYSQL_QUERY(proxysql_admin, "LOAD MYSQL QUERY RULES TO RUNTIME");
+	if (mysql_cmp) {
+		mysql_close(mysql_cmp);
 	}
-
-	if (proxysql)
-		mysql_close(proxysql);
-	if (proxysql_compression)
-		mysql_close(proxysql_compression);
-	if (mysql_compression)
-		mysql_close(mysql_compression);
-	if (mysql)
+	if (mysql) {
 		mysql_close(mysql);
-	if (proxysql_admin)
-		mysql_close(proxysql_admin);
+	}
+	if (admin) {
+		mysql_close(admin);
+	}
 
 	return exit_status();
 }
diff --git a/test/tap/tests/set_character_set-t.cpp b/test/tap/tests/set_character_set-t.cpp
index f208e532f..090101d36 100644
--- a/test/tap/tests/set_character_set-t.cpp
+++ b/test/tap/tests/set_character_set-t.cpp
@@ -13,7 +13,6 @@
  *   * character_set_client
  *   * character_set_connection
  *   * character_set_results
- *   * character_set_database
  *
  *   This checks are performed by means of the query:
  *
@@ -48,7 +47,7 @@ int main(int argc, char** argv) {
 	if(cl.getEnv())
 		return exit_status();
 
-	plan(11);
+	plan(8);
 	diag("Testing SET CHARACTER SET");
 
 	MYSQL* mysql = mysql_init(NULL);
@@ -94,7 +93,6 @@ int main(int argc, char** argv) {
 	std::string var_charset_client = "character_set_client";
 	std::string var_charset_connection = "character_set_connection";
 	std::string var_charset_results = "character_set_results";
-	std::string var_charset_database = "character_set_database";
 	std::string var_value;
 
 	show_variable(mysql, var_charset_client, var_value);
@@ -106,9 +104,6 @@ int main(int argc, char** argv) {
 	show_variable(mysql, var_charset_results, var_value);
 	ok(var_value.compare("utf8") == 0, "Initial results character set. Actual %s", var_value.c_str()); // ok_3
 
-	show_variable(mysql, var_charset_database, var_value);
-	ok(var_value.compare("utf8") == 0, "Initial database character set. Actual %s", var_value.c_str()); // ok_4
-
 	if (mysql_query(mysql, "set character set latin1")) {
 	    fprintf(stderr, "SET CHARACTER SET : Error: %s\n",
 	              mysql_error(mysql));
@@ -118,11 +113,6 @@ int main(int argc, char** argv) {
 	show_variable(mysql, var_charset_client, var_value);
 	ok(var_value.compare("latin1") == 0, "Client character set is changed. Actual %s", var_value.c_str()); // ok_5
 
-	std::string db_charset_value;
-	show_variable(mysql, var_charset_database, db_charset_value);
-
-	show_variable(mysql, var_charset_database, var_value);
-	ok(var_value.compare("utf8") == 0, "Database character set is not changed. Actual %s", var_value.c_str()); // ok_6
 
 	/*
 	 * NOTE: This check was disabled because trying to check 'character_set_connection' after issuing 'SET CHARACTER SET',
@@ -150,9 +140,6 @@ int main(int argc, char** argv) {
 	show_variable(mysql, var_charset_results, var_value);
 	ok(var_value.compare("latin1") == 0, "Results character set is correct. Actual %s", var_value.c_str()); // ok_10
 
-	show_variable(mysql, var_charset_database, var_value);
-	ok(var_value.compare("utf8") == 0, "Database character set is not changed by set names. Actual %s", var_value.c_str()); // ok_11
-
 	mysql_close(mysql);
 
 	return exit_status();
diff --git a/test/tap/tests/set_testing-240-t.cpp b/test/tap/tests/set_testing-240-t.cpp
index 485c3662a..7100bd4bd 100644
--- a/test/tap/tests/set_testing-240-t.cpp
+++ b/test/tap/tests/set_testing-240-t.cpp
@@ -541,6 +541,7 @@ int main(int argc, char *argv[]) {
 			diag("Cannot detect MySQL version");
 			return exit_status();
 		}
+		diag("Starting testing for MySQL version   is_mariadb:%d", is_mariadb);
 
 		if (strcmp(host,"localhost")==0) {
 			local = 1;
diff --git a/test/tap/tests/test_backend_conn_ping-t.cpp b/test/tap/tests/test_backend_conn_ping-t.cpp
index 123c9205a..ef168455e 100644
--- a/test/tap/tests/test_backend_conn_ping-t.cpp
+++ b/test/tap/tests/test_backend_conn_ping-t.cpp
@@ -59,6 +59,8 @@
  *   parameters this number is very high, even with extremely low values for `wait_timeout`, like
  *   `num_threads=4,wait_timeout=60,batch_size=64`, a large number of connections(`15104`) would still be
  *   maintained without issues. This is what makes this issue an artificial one.
+ *
+ *   IMPORTANT: In case of failure see note below on 'wait_timeout' definition.
  */
 
 #include <string>
@@ -83,14 +85,8 @@ using srv_cfg = vector<pair<string,int>>;
 
 #define SESSIONS_FOR_CONNECTIONS_HANDLER 64
 
-// IMPORTANT: We **always** gives ourselves `1` second grace period. Depending on MySQL connection killing
-// policy for `wait_timeout`, connections could already be killed on the edge of the interval. Also, for extra
-// safety, we gave `1` extra second to avoid possible rounding errors on time computations within MySQL.
-uint32_t grace_period = 2;
-int wait_timeout = 10 + grace_period;
-
 int max_pinged_conns(uint32_t num_threads, uint32_t ping_interval_server_msec, uint32_t wait_timeout) {
-	uint32_t ping_proc_batches = floor((wait_timeout- (grace_period+1))/float(ping_interval_server_msec/1000.0));
+	uint32_t ping_proc_batches = floor(wait_timeout/float(ping_interval_server_msec/1000.0));
 
 	return (num_threads * SESSIONS_FOR_CONNECTIONS_HANDLER) * ping_proc_batches;
 }
@@ -508,7 +504,31 @@ int main(int, char**) {
 		return EXIT_FAILURE;
 	}
 
-	uint32_t max_conns = max_pinged_conns(ext_threads.val, 2000, wait_timeout);
+	// IMPORTANT: Previously, this test gave ProxySQL only '1s' margin in the computation of the 'max
+	// connections' that can be maintained for the selected 'wait_timeout' interval. While this computation
+	// was correct, this could lead to failures due to small network stalls or slowdowns. Meaning that
+	// ProxySQL acknowledges the ping for the connection **before** MySQL actual response to it, i.e, the last
+	// time the connection was used by ProxySQL can diverge slightly from the time in which MySQL acknowledges
+	// the keep-alive. With only '1s' margin, this could result in lost connections for these slowdown
+	// scenarios.
+	//
+	// There are two main reasons to relax this margin. First, this is an artificial scenario created for this
+	// test, with a way too low 'wait_timetout', i.e, the real number of connections that ProxySQL can be kept
+	// alive with the current pinging algorithm, using a default or sensible 'wait_timeout' for most loads, is
+	// too large to even be practical. Secondly, testing this maximum number of connections that can be kept
+	// alive isn't the goal of this test, but to ensure correctness in the selection of connections to ping
+	// from the connection pool, which can be done with much smaller and less error prone numbers.
+	//
+	// Due to this, we are going to give a full extra grace interval in the computation for the maximum number
+	// of connections that could be kept alive. This should result in creating `(max conns) - (conns pinged in
+	// one interval)` connections. This should give enough room for the test not to fail even in the
+	// previously described scenarios. If further failures are detected, this **should be investigated** as
+	// could mean that something is not working as expected, either in the setup or the pinging algorithm
+	// itself.
+	int wait_timeout = 10;
+	uint32_t grace_timeout = wait_timeout - (ext_ping_intv.val / 1000) - 1;
+
+	uint32_t max_conns = max_pinged_conns(ext_threads.val, ext_ping_intv.val, grace_timeout);
 	uint32_t server_max_conns = max_conns + 1000;
 	double its = floor((max_conns - b_0) / b);
 
diff --git a/test/tap/tests/test_cacert_load_and_verify_duration-t.cpp b/test/tap/tests/test_cacert_load_and_verify_duration-t.cpp
index f75b913ee..eece0e554 100644
--- a/test/tap/tests/test_cacert_load_and_verify_duration-t.cpp
+++ b/test/tap/tests/test_cacert_load_and_verify_duration-t.cpp
@@ -1,11 +1,27 @@
+/**
+ * @file test_cacert_load_and_verify_duration-t.cpp
+ * @brief Test for OpenSSL performance regression on certificate loading.
+ * @details This test uses an internal ProxySQL test checking the following OpenSSL regression regarding
+ *  certificate loading https://github.com/openssl/openssl/issues/18814. Experimental results from the test
+ *  using different OpenSSL versions:
+ *    - openssl="3.4.1" openssl_num=30400010 time='5239 ms'
+ *    - openssl="3.2.0" openssl_num=30200000 time='5407 ms'
+ *    - openssl="3.1.8" openssl_num=30100080 time='9152 ms'
+ *    - openssl="3.1.0" openssl_num=30100000 time='9481 ms'
+ *    - openssl="3.0.16" openssl_num=30400010 time='18979 ms'
+ *    - openssl="3.0.10" openssl_num=300000 time='21212 ms'
+ *    - openssl="3.0.2" openssl_num=30000020 time='47756 ms'
+ */
+
 #include <string>
 #include <string.h>
 #include "mysql.h"
-#include "mysqld_error.h"
 #include "tap.h"
 #include "command_line.h"
 #include "utils.h"
 
+using std::string;
+
 CommandLine cl;
 
 int main() {
@@ -25,9 +41,6 @@ int main() {
 	plan(1);
 
 	int32_t WASAN = get_env_int("WITHASAN", 0);
-	// Double the value of previously failed ASAN run: '89415ms'
-	int32_t EXP_TIME = WASAN == 0 ? 20000 : 180000;
-
 	MYSQL* proxysql_admin = mysql_init(NULL);
 
 	// Initialize connection
@@ -41,6 +54,45 @@ int main() {
 		return -1;
 	}
 
+	const string select_query {
+		"SELECT variable_value FROM stats.stats_mysql_global WHERE variable_name='OpenSSL_Version_Num'"
+	}; ext_val_t<int64_t> ssl_ver_ext { mysql_query_ext_val(proxysql_admin, select_query, int64_t(-1)) };
+    if (ssl_ver_ext.err) {
+        const string err { get_ext_val_err(proxysql_admin, ssl_ver_ext) };
+        diag("Failed query   query:`%s`, err:`%s`", select_query.c_str(), err.c_str());
+        return EXIT_FAILURE;
+    }
+
+	// OPENSSL_VERSION_NUMBER: 0xMNN00PP0L
+	// https://docs.openssl.org/master/man3/OpenSSL_version/
+	const string major { std::to_string(ssl_ver_ext.val >> 28) };
+	const string minor { std::to_string((ssl_ver_ext.val & 0x0FF00000L) >> 20) };
+	const string patch { std::to_string((ssl_ver_ext.val & 0x00000FF0L) >> 4) };
+	const string version { major + "." + minor + "." + patch };
+
+	diag("Detected env   openssl=\"%s\" openssl_num=%lx ASAN=%d", version.c_str(), ssl_ver_ext.val, WASAN);
+
+	// Double the value of previously failed ASAN run, previous known time '89415ms'
+	int32_t EXP_TIME = 0;
+	const int64_t OPENSSL_3_0_0 { 0x30000000L };
+	const int64_t OPENSSL_3_2_0 { 0x30200000L };
+
+	if (ssl_ver_ext.val > OPENSSL_3_0_0 && ssl_ver_ext.val < OPENSSL_3_2_0) {
+		diag("OpenSSL version *AFFECTED* by perf regression (https://github.com/openssl/openssl/issues/18814).");
+		// Based on previous run with '61392 ms'. Extra marging for versions with perf-regressions.
+		EXP_TIME = 80000;
+	} else if (ssl_ver_ext.val >= OPENSSL_3_2_0) {
+		diag("OpenSSL version *NOT* affected by perf regression");
+		EXP_TIME = 20000;
+	}
+
+	if (WASAN) {
+		diag("Running under ASAN, doubling expected time");
+		EXP_TIME *= 2;
+	}
+
+	diag("Computed threshold for test runtime   exp_time=%d", EXP_TIME);
+
 	const std::string& ca_full_path = std::string(p_infra_datadir) + "/cert-bundle-rnd.pem";
 	diag("Setting mysql-ssl_p2s_ca to '%s'", ca_full_path.c_str());
 	const std::string& set_ssl_p2s_ca = "SET mysql-ssl_p2s_ca='" + ca_full_path + "'";
diff --git a/test/tap/tests/test_query_rules_fast_routing_algorithm-t.cpp b/test/tap/tests/test_query_rules_fast_routing_algorithm-t.cpp
index a69844709..1ae41d717 100644
--- a/test/tap/tests/test_query_rules_fast_routing_algorithm-t.cpp
+++ b/test/tap/tests/test_query_rules_fast_routing_algorithm-t.cpp
@@ -36,29 +36,6 @@ using std::vector;
 // Used for 'extract_module_host_port'
 #include "modules_server_test.h"
 
-////////////////////////////////////////////////////////////////////////////////
-//          Borrowed from test_match_eof_conn_cap.cpp - TODO: MERGE
-////////////////////////////////////////////////////////////////////////////////
-
-#include <dirent.h>
-
-#define _S(s) ( std::string {s} )
-#define _TO_S(s) ( std::to_string(s) )
-
-#define SELECT_RUNTIME_VAR "SELECT variable_value FROM runtime_global_variables WHERE variable_name="
-
-#define CHECK_EXT_VAL(val)\
-	do {\
-		if (val.err) {\
-			diag("%s:%d: Query failed   err=\"%s\"", __func__, __LINE__, val.str.c_str());\
-			return EXIT_FAILURE;\
-		}\
-	} while(0)
-
-const uint32_t USLEEP_SQLITE_LOCKED = 100;
-
-////////////////////////////////////////////////////////////////////////////////
-
 int get_query_int_res(MYSQL* admin, const string& q, int& val) {
 	MYSQL_QUERY_T(admin, q.c_str());
 	MYSQL_RES* myres = mysql_store_result(admin);
diff --git a/test/tap/tests/test_utf8mb4_as_ci-4841-t.cpp b/test/tap/tests/test_utf8mb4_as_ci-4841-t.cpp
index 63f80e16f..2a0f9dcb8 100644
--- a/test/tap/tests/test_utf8mb4_as_ci-4841-t.cpp
+++ b/test/tap/tests/test_utf8mb4_as_ci-4841-t.cpp
@@ -17,6 +17,10 @@
 #include "command_line.h"
 #include "utils.h"
 
+using std::string;
+
+const int MYSQL8_HG = get_env_int("TAP_MYSQL8_BACKEND_HG", 30);
+
 int main(int argc, char** argv) {
 	CommandLine cl;
 
@@ -44,11 +48,21 @@ int main(int argc, char** argv) {
 		return exit_status();
 	}
 
-	std::string var_collation_connection = "collation_connection";
-	std::string var_value;
+	const string select_query {
+		"SELECT /* hostgroup=" + _TO_S(MYSQL8_HG) + ";create_new_connection=1 */ @@collation_connection"
+	};
+	ext_val_t<string> var_ext { mysql_query_ext_val(mysql, select_query, string {}) };
+	if (var_ext.err) {
+		const string err { get_ext_val_err(mysql, var_ext) };
+		diag("Failed query   query:`%s`, err:`%s`", select_query.c_str(), err.c_str());
+		return EXIT_FAILURE;
+	}
 
-	show_variable(mysql, var_collation_connection, var_value, true);
-	ok(var_value.compare("utf8mb4_0900_as_ci") == 0, "collation_connection , Expected utf8mb4_0900_as_ci . Actual %s", var_value.c_str()); // ok_1
+	ok(
+		"utf8mb4_0900_as_ci" == var_ext.val,
+		"collation_connection , Expected utf8mb4_0900_as_ci . Actual %s",
+		var_ext.val.c_str()
+	); // ok_1
 
 	mysql_close(mysql);