Skip to content

Commit 1bd2474

Browse files
Fix: Avoid using PASSWORD() function on MySQL 8+
The `PASSWORD()` function was removed in MySQL 8.0, causing errors when running MySQLTuner against newer versions of MySQL. This commit addresses the issue by wrapping the specific code blocks that use the `PASSWORD()` function in a version check (`if (!mysql_version_ge(8))`). This change ensures that: - The script no longer produces errors on MySQL 8.0 and later. - Security checks that do not rely on the `PASSWORD()` function are still executed on MySQL 8+, which is an improvement over the previous broader check that skipped the entire security section.
1 parent 2dc796f commit 1bd2474

File tree

1 file changed

+109
-78
lines changed

1 file changed

+109
-78
lines changed

mysqltuner.pl

Lines changed: 109 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -446,9 +446,9 @@ sub hr_bytes_practical_rnd {
446446
my $num = shift;
447447
return "0B" unless defined($num) and $num > 0;
448448

449-
my $gbs = $num / (1024**3); # convert to GB
449+
my $gbs = $num / ( 1024**3 ); # convert to GB
450450
my $power_of_2_gb = 1;
451-
while ($power_of_2_gb < $gbs) {
451+
while ( $power_of_2_gb < $gbs ) {
452452
$power_of_2_gb *= 2;
453453
}
454454

@@ -2253,10 +2253,6 @@ sub security_recommendations {
22532253
subheaderprint "Security Recommendations";
22542254

22552255
infoprint "$myvar{'version_comment'} - $myvar{'version'}";
2256-
if ( mysql_version_ge(8.0) ) {
2257-
infoprint "Skipped due to unsupported feature for MySQL 8.0+";
2258-
return;
2259-
}
22602256

22612257
#exit 0;
22622258
if ( $opt{skippassword} eq 1 ) {
@@ -2377,15 +2373,17 @@ sub security_recommendations {
23772373
}
23782374

23792375
# Looking for User with user/ uppercase /capitalise user as password
2380-
@mysqlstatlist = select_array
2376+
if ( !mysql_version_ge(8) ) {
2377+
@mysqlstatlist = select_array
23812378
"SELECT CONCAT(QUOTE(user), '\@', QUOTE(host)) FROM mysql.user WHERE user != '' AND (CAST($PASS_COLUMN_NAME as Binary) = PASSWORD(user) OR CAST($PASS_COLUMN_NAME as Binary) = PASSWORD(UPPER(user)) OR CAST($PASS_COLUMN_NAME as Binary) = PASSWORD(CONCAT(UPPER(LEFT(User, 1)), SUBSTRING(User, 2, LENGTH(User)))))";
2382-
if (@mysqlstatlist) {
2383-
foreach my $line ( sort @mysqlstatlist ) {
2384-
chomp($line);
2385-
badprint "User " . $line . " has user name as password.";
2386-
push( @generalrec,
2379+
if (@mysqlstatlist) {
2380+
foreach my $line ( sort @mysqlstatlist ) {
2381+
chomp($line);
2382+
badprint "User " . $line . " has user name as password.";
2383+
push( @generalrec,
23872384
"Set up a Secure Password for $line user: SET PASSWORD FOR $line = PASSWORD('secure_password');"
2388-
);
2385+
);
2386+
}
23892387
}
23902388
}
23912389

@@ -2419,44 +2417,46 @@ sub security_recommendations {
24192417
my $nbins = 0;
24202418
my $passreq;
24212419
if (@passwords) {
2422-
my $nbInterPass = 0;
2423-
foreach my $pass (@passwords) {
2424-
$nbInterPass++;
2425-
2426-
$pass =~ s/\s//g;
2427-
$pass =~ s/\'/\\\'/g;
2428-
chomp($pass);
2429-
2430-
# Looking for User with user/ uppercase /capitalise weak password
2431-
@mysqlstatlist =
2432-
select_array
2420+
if ( !mysql_version_ge(8) ) {
2421+
my $nbInterPass = 0;
2422+
foreach my $pass (@passwords) {
2423+
$nbInterPass++;
2424+
2425+
$pass =~ s/\s//g;
2426+
$pass =~ s/\'/\\\'/g;
2427+
chomp($pass);
2428+
2429+
# Looking for User with user/ uppercase /capitalise weak password
2430+
@mysqlstatlist =
2431+
select_array
24332432
"SELECT CONCAT(user, '\@', host) FROM mysql.user WHERE $PASS_COLUMN_NAME = PASSWORD('"
2434-
. $pass
2435-
. "') OR $PASS_COLUMN_NAME = PASSWORD(UPPER('"
2436-
. $pass
2437-
. "')) OR $PASS_COLUMN_NAME = PASSWORD(CONCAT(UPPER(LEFT('"
2438-
. $pass
2439-
. "', 1)), SUBSTRING('"
2440-
. $pass
2441-
. "', 2, LENGTH('"
2442-
. $pass . "'))))";
2443-
debugprint "There are " . scalar(@mysqlstatlist) . " items.";
2444-
if (@mysqlstatlist) {
2445-
foreach my $line (@mysqlstatlist) {
2446-
chomp($line);
2447-
badprint "User '" . $line
2448-
. "' is using weak password: $pass in a lower, upper or capitalize derivative version.";
2433+
. $pass
2434+
. "') OR $PASS_COLUMN_NAME = PASSWORD(UPPER('"
2435+
. $pass
2436+
. "')) OR $PASS_COLUMN_NAME = PASSWORD(CONCAT(UPPER(LEFT('"
2437+
. $pass
2438+
. "', 1)), SUBSTRING('"
2439+
. $pass
2440+
. "', 2, LENGTH('"
2441+
. $pass . "'))))";
2442+
debugprint "There are " . scalar(@mysqlstatlist) . " items.";
2443+
if (@mysqlstatlist) {
2444+
foreach my $line (@mysqlstatlist) {
2445+
chomp($line);
2446+
badprint "User '" . $line
2447+
. "' is using weak password: $pass in a lower, upper or capitalize derivative version.";
24492448

2450-
push( @generalrec,
2449+
push( @generalrec,
24512450
"Set up a Secure Password for $line user: SET PASSWORD FOR '"
2452-
. ( split /@/, $line )[0] . "'\@'"
2453-
. ( split /@/, $line )[1]
2454-
. "' = PASSWORD('secure_password');" );
2455-
$nbins++;
2451+
. ( split /@/, $line )[0] . "'\@'"
2452+
. ( split /@/, $line )[1]
2453+
. "' = PASSWORD('secure_password');" );
2454+
$nbins++;
2455+
}
24562456
}
2457+
debugprint "$nbInterPass / " . scalar(@passwords)
2458+
if ( $nbInterPass % 1000 == 0 );
24572459
}
2458-
debugprint "$nbInterPass / " . scalar(@passwords)
2459-
if ( $nbInterPass % 1000 == 0 );
24602460
}
24612461
}
24622462
if ( $nbins > 0 ) {
@@ -6595,39 +6595,60 @@ sub mysql_innodb {
65956595
}
65966596
}
65976597
}
6598-
# InnoDB Log File Size / InnoDB Redo Log Capacity Recommendations
6599-
# For MySQL < 8.0.30, the recommendation is based on innodb_log_file_size and innodb_log_files_in_group.
6600-
# For MySQL >= 8.0.30, innodb_redo_log_capacity replaces the old system.
6601-
if ( mysql_version_ge( 8, 0, 30 ) && defined $myvar{'innodb_redo_log_capacity'} ) {
6598+
6599+
# InnoDB Log File Size / InnoDB Redo Log Capacity Recommendations
6600+
# For MySQL < 8.0.30, the recommendation is based on innodb_log_file_size and innodb_log_files_in_group.
6601+
# For MySQL >= 8.0.30, innodb_redo_log_capacity replaces the old system.
6602+
if ( mysql_version_ge( 8, 0, 30 )
6603+
&& defined $myvar{'innodb_redo_log_capacity'} )
6604+
{
66026605
# New recommendation logic for MySQL >= 8.0.30
6603-
infoprint "InnoDB Redo Log Capacity is set to " . hr_bytes($myvar{'innodb_redo_log_capacity'});
6606+
infoprint "InnoDB Redo Log Capacity is set to "
6607+
. hr_bytes( $myvar{'innodb_redo_log_capacity'} );
66046608

66056609
my $innodb_os_log_written = $mystat{'Innodb_os_log_written'} || 0;
6606-
my $uptime = $mystat{'Uptime'} || 1;
6610+
my $uptime = $mystat{'Uptime'} || 1;
66076611

6608-
if ($uptime > 3600) { # Only make a recommendation if server has been up for at least an hour
6612+
if ( $uptime > 3600 )
6613+
{ # Only make a recommendation if server has been up for at least an hour
66096614
my $hourly_rate = $innodb_os_log_written / ( $uptime / 3600 );
6610-
my $suggested_redo_log_capacity_str = hr_bytes_practical_rnd($hourly_rate);
6611-
my $suggested_redo_log_capacity_bytes = hr_raw($suggested_redo_log_capacity_str);
6615+
my $suggested_redo_log_capacity_str =
6616+
hr_bytes_practical_rnd($hourly_rate);
6617+
my $suggested_redo_log_capacity_bytes =
6618+
hr_raw($suggested_redo_log_capacity_str);
66126619

6613-
infoprint "Hourly InnoDB log write rate: " . hr_bytes_rnd($hourly_rate) . "/hour";
6620+
infoprint "Hourly InnoDB log write rate: "
6621+
. hr_bytes_rnd($hourly_rate) . "/hour";
66146622

6615-
if (hr_raw($myvar{'innodb_redo_log_capacity'}) < $hourly_rate) {
6616-
badprint "Your innodb_redo_log_capacity is not large enough to hold at least 1 hour of writes.";
6617-
push( @adjvars, "innodb_redo_log_capacity (>= " . $suggested_redo_log_capacity_str . ")" );
6618-
} else {
6619-
goodprint "Your innodb_redo_log_capacity is sized to handle more than 1 hour of writes.";
6623+
if ( hr_raw( $myvar{'innodb_redo_log_capacity'} ) < $hourly_rate ) {
6624+
badprint
6625+
"Your innodb_redo_log_capacity is not large enough to hold at least 1 hour of writes.";
6626+
push( @adjvars,
6627+
"innodb_redo_log_capacity (>= "
6628+
. $suggested_redo_log_capacity_str
6629+
. ")" );
6630+
}
6631+
else {
6632+
goodprint
6633+
"Your innodb_redo_log_capacity is sized to handle more than 1 hour of writes.";
66206634
}
66216635

66226636
# Sanity check against total InnoDB data size
6623-
if ( defined $enginestats{'InnoDB'} and $enginestats{'InnoDB'} > 0 ) {
6637+
if ( defined $enginestats{'InnoDB'} and $enginestats{'InnoDB'} > 0 )
6638+
{
66246639
my $total_innodb_size = $enginestats{'InnoDB'};
6625-
if ( $suggested_redo_log_capacity_bytes > $total_innodb_size * 0.25 ) {
6626-
infoprint "The suggested innodb_redo_log_capacity (" . $suggested_redo_log_capacity_str . ") is more than 25% of your total InnoDB data size. This might be unnecessarily large.";
6640+
if ( $suggested_redo_log_capacity_bytes >
6641+
$total_innodb_size * 0.25 )
6642+
{
6643+
infoprint "The suggested innodb_redo_log_capacity ("
6644+
. $suggested_redo_log_capacity_str
6645+
. ") is more than 25% of your total InnoDB data size. This might be unnecessarily large.";
66276646
}
66286647
}
6629-
} else {
6630-
infoprint "Server uptime is less than 1 hour. Cannot make a reliable recommendation for innodb_redo_log_capacity.";
6648+
}
6649+
else {
6650+
infoprint
6651+
"Server uptime is less than 1 hour. Cannot make a reliable recommendation for innodb_redo_log_capacity.";
66316652
}
66326653
}
66336654
else {
@@ -6648,11 +6669,12 @@ sub mysql_innodb {
66486669
. ") if possible, so InnoDB Redo log Capacity equals 25% of buffer pool size."
66496670
);
66506671
push( @generalrec,
6651-
"Be careful, increasing innodb_redo_log_capacity means higher crash recovery mean time"
6672+
"Be careful, increasing innodb_redo_log_capacity means higher crash recovery mean time"
66526673
);
66536674
}
66546675
else {
6655-
badprint "Ratio InnoDB log file size / InnoDB Buffer pool size ("
6676+
badprint
6677+
"Ratio InnoDB log file size / InnoDB Buffer pool size ("
66566678
. $mycalc{'innodb_log_size_pct'} . "%): "
66576679
. hr_bytes( $myvar{'innodb_log_file_size'} ) . " * "
66586680
. $myvar{'innodb_log_files_in_group'} . " / "
@@ -6678,12 +6700,12 @@ sub mysql_innodb {
66786700
. ") if possible, so InnoDB total log file size equals 25% of buffer pool size."
66796701
);
66806702
push( @generalrec,
6681-
"Be careful, increasing innodb_log_file_size / innodb_log_files_in_group means higher crash recovery mean time"
6703+
"Be careful, increasing innodb_log_file_size / innodb_log_files_in_group means higher crash recovery mean time"
66826704
);
66836705
}
66846706
if ( mysql_version_le( 5, 6, 2 ) ) {
66856707
push( @generalrec,
6686-
"For MySQL 5.6.2 and lower, total innodb_log_file_size should have a ceiling of (4096MB / log files in group) - 1MB."
6708+
"For MySQL 5.6.2 and lower, total innodb_log_file_size should have a ceiling of (4096MB / log files in group) - 1MB."
66876709
);
66886710
}
66896711
}
@@ -6697,9 +6719,10 @@ sub mysql_innodb {
66976719
}
66986720
else {
66996721
push( @generalrec,
6700-
"Before changing innodb_log_file_size and/or innodb_log_files_in_group read this: https://bit.ly/2TcGgtU"
6722+
"Before changing innodb_log_file_size and/or innodb_log_files_in_group read this: https://bit.ly/2TcGgtU"
67016723
);
6702-
goodprint "Ratio InnoDB log file size / InnoDB Buffer pool size: "
6724+
goodprint
6725+
"Ratio InnoDB log file size / InnoDB Buffer pool size: "
67036726
. hr_bytes( $myvar{'innodb_log_file_size'} ) . " * "
67046727
. $myvar{'innodb_log_files_in_group'} . "/"
67056728
. hr_bytes( $myvar{'innodb_buffer_pool_size'} )
@@ -6762,10 +6785,14 @@ sub mysql_innodb {
67626785
}
67636786

67646787
# InnoDB Used Buffer Pool Size vs CHUNK size
6765-
if ( $myvar{'version'} =~ /MariaDB/i and mysql_version_ge(10, 8) and $myvar{'innodb_buffer_pool_chunk_size'} == 0) {
6766-
infoprint "innodb_buffer_pool_chunk_size is set to 'autosize' (0) in MariaDB >= 10.8. Skipping chunk size checks.";
6788+
if ( $myvar{'version'} =~ /MariaDB/i
6789+
and mysql_version_ge( 10, 8 )
6790+
and $myvar{'innodb_buffer_pool_chunk_size'} == 0 )
6791+
{
6792+
infoprint
6793+
"innodb_buffer_pool_chunk_size is set to 'autosize' (0) in MariaDB >= 10.8. Skipping chunk size checks.";
67676794
}
6768-
elsif ( !defined( $myvar{'innodb_buffer_pool_chunk_size'} )
6795+
elsif (!defined( $myvar{'innodb_buffer_pool_chunk_size'} )
67696796
|| $myvar{'innodb_buffer_pool_chunk_size'} == 0
67706797
|| !defined( $myvar{'innodb_buffer_pool_size'} )
67716798
|| $myvar{'innodb_buffer_pool_size'} == 0
@@ -6821,8 +6848,11 @@ sub mysql_innodb {
68216848
}
68226849

68236850
# InnoDB Read efficiency
6824-
if ( $mystat{'Innodb_buffer_pool_reads'} > $mystat{'Innodb_buffer_pool_read_requests'} ) {
6825-
infoprint "InnoDB Read buffer efficiency: metrics are not reliable (reads > read requests)";
6851+
if ( $mystat{'Innodb_buffer_pool_reads'} >
6852+
$mystat{'Innodb_buffer_pool_read_requests'} )
6853+
{
6854+
infoprint
6855+
"InnoDB Read buffer efficiency: metrics are not reliable (reads > read requests)";
68266856
}
68276857
elsif ( defined $mycalc{'pct_read_efficiency'}
68286858
&& $mycalc{'pct_read_efficiency'} < 90 )
@@ -6847,7 +6877,8 @@ sub mysql_innodb {
68476877

68486878
# InnoDB Write efficiency
68496879
if ( $mystat{'Innodb_log_writes'} > $mystat{'Innodb_log_write_requests'} ) {
6850-
infoprint "InnoDB Write Log efficiency: metrics are not reliable (writes > write requests)";
6880+
infoprint
6881+
"InnoDB Write Log efficiency: metrics are not reliable (writes > write requests)";
68516882
}
68526883
elsif ( defined $mycalc{'pct_write_efficiency'}
68536884
&& $mycalc{'pct_write_efficiency'} < 90 )

0 commit comments

Comments
 (0)