Bug #99101 SELECT .. LOCK IN SHARE MODE requires LOCK TABLES grant
Submitted: 27 Mar 2020 19:19 Modified: 1 Sep 2020 18:07
Reporter: Matthew Boehm Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: DML Severity:S3 (Non-critical)
Version:8.0, 8.0.11, 8.0.19 OS:Any
Assigned to: CPU Architecture:Any

[27 Mar 2020 19:19] Matthew Boehm
Description:
In MySQL 5.7, it was not necessary to have the LOCK TABLES grant if you executed SELECT ... LOCK IN SHARE MODE. Now, in 8.0, this extra grant is required. This grant is not required for UPDATE statements, which also lock rows during transactions.

How to repeat:
* Install MySQL 8.0
* Create user with SELECT privs
* Attempt to SELECT .. LOCK IN SHARE MODE using above user.
* Observe failure.

--- 5.7
bash-4.2$ mysql -ulocktest -plocktest1 world
mysql: [Warning] Using a password on the command line interface can be insecure.
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 5.7.27-30 Percona Server (GPL), Release 30, Revision 8916819

Copyright (c) 2009-2019 Percona LLC and/or its affiliates
Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> SHOW GRANTS;
+-----------------------------------------------------+
| Grants for locktest@localhost                       |
+-----------------------------------------------------+
| GRANT USAGE ON *.* TO 'locktest'@'localhost'        |
| GRANT SELECT ON `world`.* TO 'locktest'@'localhost' |
+-----------------------------------------------------+
2 rows in set (0.00 sec)

mysql> SELECT * FROM city WHERE name = 'Houston';
+------+---------+-------------+----------+------------+
| ID   | Name    | CountryCode | District | Population |
+------+---------+-------------+----------+------------+
| 3796 | Houston | USA         | Texas    |    1953631 |
+------+---------+-------------+----------+------------+
1 row in set (0.01 sec)

mysql> SELECT * FROM city WHERE name = 'Houston' LOCK IN  SHARE MODE;
+------+---------+-------------+----------+------------+
| ID   | Name    | CountryCode | District | Population |
+------+---------+-------------+----------+------------+
| 3796 | Houston | USA         | Texas    |    1953631 |
+------+---------+-------------+----------+------------+
1 row in set (0.00 sec)

--- 8.0
root@502563941daf:/# mysql -ulocktest -plocktest1234 world
mysql: [Warning] Using a password on the command line interface can be insecure.
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 312
Server version: 8.0.16 MySQL Community Server - GPL

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show grants for 'locktest'@'localhost';
+-----------------------------------------------------+
| Grants for locktest@localhost                       |
+-----------------------------------------------------+
| GRANT USAGE ON *.* TO `locktest`@`localhost`        |
| GRANT SELECT ON `world`.* TO `locktest`@`localhost` |
+-----------------------------------------------------+
2 rows in set (0.00 sec)

mysql> SELECT * FROM city WHERE name = 'Houston';
+------+---------+-------------+----------+------------+
| ID   | Name    | CountryCode | District | Population |
+------+---------+-------------+----------+------------+
| 3796 | Houston | USA         | Texas    |    1953631 |
+------+---------+-------------+----------+------------+
1 row in set (0.03 sec)

mysql> SELECT * FROM city WHERE name = 'Houston' LOCK IN SHARE MODE;
ERROR 1142 (42000): SELECT with locking clause command denied to user 'locktest'@'localhost' for table 'city'

(as root user, add necessary grant)
mysql> GRANT LOCK TABLES ON world.* TO 'locktest'@'localhost';                                                                                                                                                                                                              Query OK, 0 rows affected, 1 warning (0.14 sec)

mysql> show grants for locktest@localhost;
+------------------------------------------------------------------+
| Grants for locktest@localhost                                    |
+------------------------------------------------------------------+
| GRANT USAGE ON *.* TO `locktest`@`localhost`                     |
| GRANT SELECT, LOCK TABLES ON `world`.* TO `locktest`@`localhost` |
+------------------------------------------------------------------+
2 rows in set (0.00 sec)

(as app user)
mysql> SELECT * FROM city WHERE name = 'Houston' LOCK IN  SHARE MODE;
+------+---------+-------------+----------+------------+
| ID   | Name    | CountryCode | District | Population |
+------+---------+-------------+----------+------------+
| 3796 | Houston | USA         | Texas    |    1953631 |
+------+---------+-------------+----------+------------+
1 row in set (0.00 sec)

Suggested fix:
To maintain compatibility with 5.7, I suggest the LOCK IN SHARE MODE behavior be reverted to comply with 5.7 behavior. Or the documentation needs to be updated to reflect this new behavior.
[30 Mar 2020 9:47] MySQL Verification Team
Hello Matthew,

Thank you for the report.

regards,
Umesh
[1 Sep 2020 18:07] Daniel Price
Posted by developer:
 
Fixed as of the upcoming 8.0.22 release, and here's the proposed changelog entry from the documentation team:

A SELECT ... FOR SHARE statement now only requires the SELECT privilege.
Previously, the SELECT privilege was required with at least one of the
DELETE, LOCK TABLES, or UPDATE privileges. 

Other documentation updates (should appear online soon):

Locking Reads documentation update:
https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html

8.0.1 changelog entry update for WL3597:
https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-1.html