ERROR 1143 (42000): SELECT command denied - mysql

I use a user who has the update privileges to execute a sql:
update stu set age = 27 where name='zjw';
I got this error:
ERROR 1143 (42000): SELECT command denied to user
'update_user'#'localhost' for column 'name' in table 'stu'
The table like this:
CREATE TABLE `stu` (
`id` int(11) NOT NULL,
`name` varchar(20) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
)
update_user's privileges is:
grant update on *.* to 'update_user'#'%';
MySQL version is 5.1.73.
thanks.

When you execute
UPDATE `stu` SET age = 27 WHERE name = 'zjw';
the SQL engine has to first select the rows it needs to update.
Therefore, if you do not have the SELECT privilege, you cannot perform such update, even if you have the UPDATE privilege.
Check out the Manual for the Grant Syntax.

#Robin as per your last comment, try to understand your update statement-
UPDATE `stu` SET age = 27 WHERE name = 'zjw';
Your above update statement first try to fetch the records where name='zjw', so if your name column is indexed then select use index and select directly only records those have value 'zjw' else it will scan whole table and select 'zjw' wherever in table.
Means first mysql use select statement internally before update, so you also need select privileges with any other privileges like update/delete etc.
so your grant command should be-
GRANT SELECT, UPDATE on db.* to 'myuser'#'localhost' identified by 'mypass';
You should give permission only specific IP or localhost as per requirement instead of globally by '%' which is risky.

because when where clause is used in update, the datebase will select the rows that meet the where condition, so select privilege is needed while granting update privilege.
The SELECT privilege is also needed for other statements that read column values. For example, SELECT is needed for columns referenced on the right hand side of col_name=expr assignment in UPDATE statements or for columns named in the WHERE clause of DELETE or UPDATE statements.
mysql manual here

Related

MySQL view using self-defined function cannot be selected (privileges error) with prepared statement but direct query works

while building a by now slightly complex database for a private project, we found an issue that may as well be a bug, but I wanted to ask for some advice here because maybe I am just wrong in my assumptions.
Preamble: All VIEWs and FUNCTIONs are created as DEFINER = `root`#`localhost` SQL SECURITY DEFINER. Just the final user that makes a connection is limited to what he can use.
For FUNCTIONs (this maybe is MySQL Workbench behaviour), the SQL SECURITY DEFINER never is transcribed to the DDL(?), but looking at SELECT SECURITY_TYPE FROM information_schema.routines, there is definitely written DEFINER.
Main issue: So the problem arises when I try to use a FUNCTION on a column of a VIEW, where the FUNCTION uses a VIEW itself and the user has just SELECT PRIVILEGES on the first mentioned VIEW.
If I do a straight SELECT, everything works as expected, but if I put the SELECT in a PREPAREd statement and EXECUTE this, I get an Error Code: 1356. View 'test.usableview' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them error.
MySQL Server used is 8.0.22 at the moment still on Windows 10, v8.0.27 (most recent release) has the same issue.
Minimal example:
as a root user do the following:
CREATE SCHEMA `test`;
USE `test`;
CREATE TABLE IF NOT EXISTS `test`.`basetable_noRights` (
`id` INT NOT NULL AUTO_INCREMENT,
`something` VARCHAR(45) NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
INSERT INTO `test`.`basetable_noRights` VALUES (1, 'test');
CREATE TABLE IF NOT EXISTS `test`.`basetable_noRights2` (
`id` INT NOT NULL AUTO_INCREMENT,
`something` VARCHAR(45) NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
INSERT INTO `test`.`basetable_noRights2` VALUES (1, 'finally not visible');
CREATE OR REPLACE VIEW `test`.`firstlevelview` AS
SELECT 1 AS id, CONCAT(something, ' 1') AS foo FROM `test`.`basetable_noRights`;
DELIMITER $$
CREATE FUNCTION `user_has_no_rights_function`(i INT) RETURNS VARCHAR(99) CHARSET utf8
READS SQL DATA
begin
SELECT foo INTO #var FROM `test`.`firstlevelview` WHERE id = 1;
return #var;
end$$
DELIMITER ;
CREATE OR REPLACE VIEW `test`.`usableview` AS
SELECT user_has_no_rights_function(id) AS final FROM`test`.`basetable_noRights2` WHERE id = 1;
CREATE OR REPLACE VIEW `test`.`view_without_function` AS
SELECT snd.foo, fst.something FROM `test`.`firstlevelview` snd, `test`.`basetable_noRights` fst;
CREATE USER 'foo'#'%' IDENTIFIED BY 'bar';
GRANT SELECT ON TABLE `test`.`usableview` TO 'foo'#'%';
GRANT SELECT ON TABLE `test`.`view_without_function` TO 'foo'#'%';
FLUSH PRIVILEGES;
login as newly created foo user. Compare:
SELECT * FROM view_without_function; -- works
PREPARE asdf FROM "SELECT * FROM view_without_function";
EXECUTE asdf; -- works
SELECT * FROM usableview; -- works
PREPARE asdf2 FROM "SELECT * FROM usableview";
EXECUTE asdf2; -- does not work
By the way, when changing the function to SELECT from a TABLE and not a VIEW, everything works as expected again.
Maybe this is all by design, but in that case I don't understand the design. Maybe actually for prepared statements one needs to GRANT more privileges and we were just lucky that everything worked until here.
Maybe it is just some serverside setting that I don't know of?
I am especially looking forward for all "You need to grant privileges for the underlying tables", although we already saw in the example above that this ain't (completly) true because the straight SELECT works and the MySQL documentation also states that the privileges of (in our case) the root definer are used ;)
The behaviour described is now a confirmed bug, see https://bugs.mysql.com/bug.php?id=105807.

A new field is added to the table that is not allowed to be empty, and then it is changed to be allowed to be empty, resulting in a query error

MYSQL [user]> alter table user add age int(1) not null;
MYSQL [user]> alter table user modify age int(1) null;
MYSQL [user]> select * from user limit 1;
database having dataļ¼
ERROR 1104 (42000): The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay

Error Code: 1143 SELECT Command Denied Whenever I try Running an Update Query, even Though I Have Both UPDATE and SELECT permissions

I get Error Code: 1143. SELECT command denied to user whenever I try to run an UPDATE query with a condition statement.
I have SELECT permissions on all tables in the database, and UPDATE permissions on certain fields in certain tables.
GRANT SELECT ON `Base`.* TO `php_role`;
GRANT UPDATE (`amount`) ON `Base`.`cart` TO `php_role`;
I am able to run the following SELECT query without any errors:
SELECT * FROM `cart` WHERE `subscription_id` = 0;
but when I try running an UPDATE query, I get the error:
UPDATE `cart` SET `amount` = 0 WHERE `subscription_id` = 0;
Even if I grant myself UPDATE permissions on the entire table, I still get the error.
The only I found to fix it, was by granting UPDATE permissions on the entire database.
Minimal Reproducible Example:
As Root, create the database, table, and user
CREATE DATABASE test_db;
USE test_db;
CREATE TABLE test(
p_id INT,
val INT,
PRIMARY KEY(p_id)
);
CREATE ROLE test_role;
CREATE USER test_user IDENTIFIED BY 'password';
GRANT SELECT ON test_db.* TO test_role;
GRANT INSERT ON test_db.* TO test_role;
GRANT UPDATE (val) ON test_db.test TO test_role;
GRANT test_role TO test_user;
SET DEFAULT ROLE test_role TO test_user;
As the newly created user, login and try running an UPDATE query
USE test_db;
UPDATE test SET val = 0 WHERE p_id = 0;
The UPDATE query results in the error, while the following query works fine:
SELECT * FROM test;

Can GRANT USAGE to #user'%' for a specific column table work?

novice in mysql here .
I have a database created in mysql called 'productes' and 'productos' is one of the database tables.
Productos has the following columns :
CREATE TABLE Productos
(
IdProducto INT NOT NULL AUTO_INCREMENT,
NombreProducto CHAR(40) NOT NULL,
IdProveedor INT,
IdCategoria INT,
PrecioUnidad DECIMAL(20,4),
UnidadesEnExistenci SMALLINT,
Suspendido TINYINT,
KEY (IdCategoria),
KEY (IdCategoria),
KEY (IdProveedor),
KEY (NombreProducto),
PRIMARY KEY (IdProducto),
KEY (IdProveedor)
);
What I tried to do as root user from the command line was the following :
mysql>GRANT USAGE (PrecioUnidad) ON productes.productos TO pepe#'%' IDENTIFIED BY
'pepe';
(i.e deny all access to user 'pepe' from all the domain machines to the column 'PrecioUnidad' of the table productos )
And I got an error(ERROR 1064) saying that I have an error in my syntax .
I thought to grant privileges to the rest of the columns of the table and exclude the specific one to get the desired result but I thought that maybe there is another way .
So my question is this : Can grant usage be applied for a specific column table and I'm just missing something here , or is there another way to disallow all privileges for only one column table ?
You can create a view with all columns but PrecioUnidad and then grant (allow) pepe access to that view.
CREATE VIEW pepes_productos AS
SELECT
IdProducto,
NombreProducto,
IdProveedor,
IdCategoria,
UnidadesEnExistenci,
Suspendido
FROM productos
From the Mysql Manual
Column Privileges
Column privileges apply to single columns in a given table. Each
privilege to be granted at the column level must be followed by the
column or columns, enclosed within parentheses.
GRANT SELECT (col1), INSERT (col1,col2) ON mydb.mytbl TO
'someuser'#'somehost'; The permissible priv_type values for a column
(that is, when you use a column_list clause) are INSERT, SELECT, and
UPDATE.
MySQL stores column privileges in the mysql.columns_priv table.
http://dev.mysql.com/doc/refman/5.1/en/grant.html#grant-column-privileges

MySQL: find all users with a given permission for a db

Looking for a query to find all users who have a given permission (EG execute) for a given database.
Rationale: cleaning up ancient stored procedures and want to know who might be using them.
I can imagine a plug-n-chug SP where I loop through all the values returned from "show grants for xxx" but I'm hoping there is a better way.
select * from mysql.user where `Execute_priv` = 'Y'
Replace Execute_priv with the column name of the other priviledges you're after
For privileges on a DB by DB basis, try querying the mysql.db table:
select * from mysql.db where `Db` = 'databasename' and `Execute_priv` = 'Y'