diff --git a/src/box/errcode.h b/src/box/errcode.h
index 55299b73594713621d5247959e714502fb211fef..be8dab27d9c13e89efc5cec2be3cdd4cc5c45e95 100644
--- a/src/box/errcode.h
+++ b/src/box/errcode.h
@@ -249,6 +249,7 @@ struct errcode_record {
 	/*194 */_(ER_MULTIKEY_INDEX_MISMATCH,	"Field %s is used as multikey in one index and as single key in another") \
 	/*195 */_(ER_CREATE_CK_CONSTRAINT,	"Failed to create check constraint '%s': %s") \
 	/*196 */_(ER_CK_CONSTRAINT_FAILED,	"Check constraint failed '%s': %s") \
+	/*197 */_(ER_SQL_COLUMN_COUNT,		"Unequal number of entries in row expression: left side has %u, but right side - %u") \
 
 /*
  * !IMPORTANT! Please follow instructions at start of the file
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index 898d16cf379ea11f453fa223b272bb0839cea802..d7104d8a0824ab6db36a929816d5725873e3516c 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -2945,22 +2945,16 @@ int
 sqlExprCheckIN(Parse * pParse, Expr * pIn)
 {
 	int nVector = sqlExprVectorSize(pIn->pLeft);
-	const char *err;
 	if ((pIn->flags & EP_xIsSelect)) {
 		if (nVector != pIn->x.pSelect->pEList->nExpr) {
-			err = "sub-select returns %d columns - expected %d";
 			int expr_count = pIn->x.pSelect->pEList->nExpr;
-			diag_set(ClientError, ER_SQL_PARSER_GENERIC,
-				 tt_sprintf(err, expr_count, nVector));
+			diag_set(ClientError, ER_SQL_COLUMN_COUNT, nVector,
+				 expr_count);
 			pParse->is_aborted = true;
 			return 1;
 		}
 	} else if (nVector != 1) {
-		assert((pIn->pLeft->flags & EP_xIsSelect) != 0);
-		int expr_count = pIn->pLeft->x.pSelect->pEList->nExpr;
-		err = tt_sprintf("sub-select returns %d columns - expected 1",
-				 expr_count);
-		diag_set(ClientError, ER_SQL_PARSER_GENERIC, err);
+		diag_set(ClientError, ER_SQL_COLUMN_COUNT, nVector, 1);
 		pParse->is_aborted = true;
 		return 1;
 	}
@@ -4111,10 +4105,8 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
 			testcase(op == TK_SELECT);
 			if (op == TK_SELECT
 			    && (nCol = pExpr->x.pSelect->pEList->nExpr) != 1) {
-				const char *err = "sub-select returns %d "\
-						  "columns - expected 1";
-				diag_set(ClientError, ER_SQL_PARSER_GENERIC,
-					 tt_sprintf(err, nCol));
+				diag_set(ClientError, ER_SQL_COLUMN_COUNT,
+					 nCol, 1);
 				pParse->is_aborted = true;
 			} else {
 				return sqlCodeSubselect(pParse, pExpr, 0);
diff --git a/src/box/sql/resolve.c b/src/box/sql/resolve.c
index fdf3703da2c380c617c26acd03ae8125df9c64ad..0b90edd062fa3fffb1e8de4112f4abd474d9fdbd 100644
--- a/src/box/sql/resolve.c
+++ b/src/box/sql/resolve.c
@@ -776,15 +776,8 @@ resolveExprStep(Walker * pWalker, Expr * pExpr)
 				nRight = sqlExprVectorSize(pExpr->pRight);
 			}
 			if (nLeft != nRight) {
-				testcase(pExpr->op == TK_EQ);
-				testcase(pExpr->op == TK_NE);
-				testcase(pExpr->op == TK_LT);
-				testcase(pExpr->op == TK_LE);
-				testcase(pExpr->op == TK_GT);
-				testcase(pExpr->op == TK_GE);
-				testcase(pExpr->op == TK_BETWEEN);
-				diag_set(ClientError, ER_SQL_PARSER_GENERIC,
-					 "row value misused");
+				diag_set(ClientError, ER_SQL_COLUMN_COUNT,
+					 nLeft, nRight);
 				pParse->is_aborted = true;
 			}
 			break;
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index a257e7204669bcc05e4831a144c0515983f91991..7c8da251ecea108fb92dc038bc36c8108ebaf33e 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -3582,12 +3582,10 @@ substExpr(Parse * pParse,	/* Report errors here */
 			assert(pExpr->pLeft == 0 && pExpr->pRight == 0);
 			if (sqlExprIsVector(pCopy)) {
 				assert((pCopy->flags & EP_xIsSelect) != 0);
-				const char *err = "sub-select returns %d "\
-						  "columns - expected 1";
 				int expr_count =
 					pCopy->x.pSelect->pEList->nExpr;
-				diag_set(ClientError, ER_SQL_PARSER_GENERIC,
-					 tt_sprintf(err, expr_count));
+				diag_set(ClientError, ER_SQL_COLUMN_COUNT,
+					 expr_count, 1);
 				pParse->is_aborted = true;
 			} else {
 				pNew = sqlExprDup(db, pCopy, 0);
diff --git a/test/box/misc.result b/test/box/misc.result
index c293ccc2ad288e4f00436f5771772f8012c9b82f..dab8549bd1a15ad0bf666c77e8ae335f1cef9508 100644
--- a/test/box/misc.result
+++ b/test/box/misc.result
@@ -524,6 +524,7 @@ t;
   194: box.error.MULTIKEY_INDEX_MISMATCH
   195: box.error.CREATE_CK_CONSTRAINT
   196: box.error.CK_CONSTRAINT_FAILED
+  197: box.error.SQL_COLUMN_COUNT
 ...
 test_run:cmd("setopt delimiter ''");
 ---
diff --git a/test/sql-tap/in1.test.lua b/test/sql-tap/in1.test.lua
index 76112cff9ee08d2dea65f2448b0e6ca172dedf28..bc0dfb8cf8e3d9e0a646db0b46434dad6b282b1e 100755
--- a/test/sql-tap/in1.test.lua
+++ b/test/sql-tap/in1.test.lua
@@ -594,7 +594,7 @@ test:do_catchsql_test(
         SELECT b FROM t1 WHERE a NOT IN tb;
     ]], {
         -- <in-9.4>
-        1, "sub-select returns 2 columns - expected 1"
+        1, "Unequal number of entries in row expression: left side has 1, but right side - 2"
         -- </in-9.4>
     })
 
@@ -677,7 +677,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <in-12.2>
-        1, "sub-select returns 2 columns - expected 1"
+        1, "Unequal number of entries in row expression: left side has 1, but right side - 2"
         -- </in-12.2>
     })
 
@@ -689,7 +689,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <in-12.3>
-        1, "sub-select returns 2 columns - expected 1"
+        1, "Unequal number of entries in row expression: left side has 1, but right side - 2"
         -- </in-12.3>
     })
 
@@ -701,7 +701,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <in-12.4>
-        1, "sub-select returns 2 columns - expected 1"
+        1, "Unequal number of entries in row expression: left side has 1, but right side - 2"
         -- </in-12.4>
     })
 
@@ -713,7 +713,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <in-12.5>
-        1, "sub-select returns 2 columns - expected 1"
+        1, "Unequal number of entries in row expression: left side has 1, but right side - 2"
         -- </in-12.5>
     })
 
@@ -823,7 +823,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <in-12.14>
-        1, "sub-select returns 2 columns - expected 1"
+        1, "Unequal number of entries in row expression: left side has 1, but right side - 2"
         -- </in-12.14>
     })
 
@@ -1058,7 +1058,7 @@ test:do_catchsql_test(
         SELECT 0 WHERE (SELECT 0,0) OR (0 IN (1,2));
     ]], {
         -- <in-13.15>
-        1, "sub-select returns 2 columns - expected 1"
+        1, "Unequal number of entries in row expression: left side has 2, but right side - 1"
         -- </in-13.15>
     })
 
diff --git a/test/sql-tap/select7.test.lua b/test/sql-tap/select7.test.lua
index f2a071d04991c3b97af9f7a1f3b018784a7edad6..3b36d5754abd4609a33b8db5f27a978f77751b30 100755
--- a/test/sql-tap/select7.test.lua
+++ b/test/sql-tap/select7.test.lua
@@ -130,7 +130,7 @@ test:do_catchsql_test(
         SELECT 5 IN (SELECT a,b FROM t2);
     ]], {
         -- <select7-5.1>
-        1, "sub-select returns 2 columns - expected 1"
+        1, "Unequal number of entries in row expression: left side has 1, but right side - 2"
         -- </select7-5.1>
     })
 
@@ -140,7 +140,7 @@ test:do_catchsql_test(
         SELECT 5 IN (SELECT * FROM t2);
     ]], {
         -- <select7-5.2>
-        1, "sub-select returns 2 columns - expected 1"
+        1, "Unequal number of entries in row expression: left side has 1, but right side - 2"
         -- </select7-5.2>
     })
 
@@ -150,7 +150,7 @@ test:do_catchsql_test(
         SELECT 5 IN (SELECT a,b FROM t2 UNION SELECT b,a FROM t2);
     ]], {
         -- <select7-5.3>
-        1, "sub-select returns 2 columns - expected 1"
+        1, "Unequal number of entries in row expression: left side has 1, but right side - 2"
         -- </select7-5.3>
     })
 
@@ -160,7 +160,7 @@ test:do_catchsql_test(
         SELECT 5 IN (SELECT * FROM t2 UNION SELECT * FROM t2);
     ]], {
         -- <select7-5.4>
-        1, "sub-select returns 2 columns - expected 1"
+        1, "Unequal number of entries in row expression: left side has 1, but right side - 2"
         -- </select7-5.4>
     })
 
diff --git a/test/sql-tap/sql-errors.test.lua b/test/sql-tap/sql-errors.test.lua
index a8d39472d2e538e652b07dcd35474e38f019b89c..636242129ea2901b70cbb2c68cdcc4a5fbc3b3b0 100755
--- a/test/sql-tap/sql-errors.test.lua
+++ b/test/sql-tap/sql-errors.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(47)
+test:plan(63)
 
 test:execsql([[
 	CREATE TABLE t0 (i INT PRIMARY KEY, a INT);
@@ -462,7 +462,7 @@ test:do_catchsql_test(
 		SELECT (1,2,3) == (1,2,3,4);
 	]], {
 		-- <sql-errors-1.41>
-		1,"row value misused"
+		1,"Unequal number of entries in row expression: left side has 3, but right side - 4"
 		-- </sql-errors-1.41>
 	})
 
@@ -526,4 +526,164 @@ test:do_catchsql_test(
 		-- </sql-errors-1.47>
 	})
 
+test:do_catchsql_test(
+	"sql-errors-1.48",
+	[[
+		SELECT (1,2) IN (1,2,3);
+	]], {
+		-- <sql-errors-1.48>
+		1, "Unequal number of entries in row expression: left side has 2, but right side - 1"
+		-- </sql-errors-1.48>
+	})
+
+test:do_catchsql_test(
+	"sql-errors-1.49",
+	[[
+		SELECT (1,2) IN (SELECT (1), (2), (3));
+	]], {
+		-- <sql-errors-1.49>
+		1, "Unequal number of entries in row expression: left side has 2, but right side - 3"
+		-- </sql-errors-1.49>
+	})
+
+test:do_catchsql_test(
+	"sql-errors-1.50",
+	[[
+		SELECT (1,2) IN (VALUES (1,2,3), (2,3,4));
+	]], {
+		-- <sql-errors-1.50>
+		1, "Unequal number of entries in row expression: left side has 2, but right side - 3"
+		-- </sql-errors-1.50>
+	})
+
+test:do_catchsql_test(
+	"sql-errors-1.51",
+	[[
+		SELECT (1,2) IN (SELECT * from (VALUES (1,2,3), (2,3,4)));
+	]], {
+		-- <sql-errors-1.51>
+		1, "Unequal number of entries in row expression: left side has 2, but right side - 3"
+		-- </sql-errors-1.51>
+	})
+
+test:do_catchsql_test(
+	"sql-errors-1.52",
+	[[
+		SELECT (1) IN (1,2,3);
+	]], {
+		-- <sql-errors-1.52>
+		0, {true}
+		-- </sql-errors-1.52>
+	})
+
+test:do_catchsql_test(
+	"sql-errors-1.53",
+	[[
+		SELECT (1,2,3) IN (SELECT (1), (2), (3));
+	]], {
+		-- <sql-errors-1.53>
+		0, {true}
+		-- </sql-errors-1.53>
+	})
+
+test:do_catchsql_test(
+	"sql-errors-1.54",
+	[[
+		SELECT (1,2,3) IN (VALUES (1,2,3), (2,3,4));
+	]], {
+		-- <sql-errors-1.54>
+		0, {true}
+		-- </sql-errors-1.54>
+	})
+
+test:do_catchsql_test(
+	"sql-errors-1.55",
+	[[
+		SELECT (1,2,3) IN (SELECT * from (VALUES (1,2,3), (2,3,4)));
+	]], {
+		-- <sql-errors-1.55>
+		0, {true}
+		-- </sql-errors-1.55>
+	})
+
+test:do_catchsql_test(
+	"sql-errors-1.56",
+	[[
+		SELECT (SELECT * FROM (VALUES (1,2))) IN (1,2,3);
+	]], {
+		-- <sql-errors-1.56>
+		1, "Unequal number of entries in row expression: left side has 2, but right side - 1"
+		-- </sql-errors-1.56>
+	})
+
+test:do_catchsql_test(
+	"sql-errors-1.57",
+	[[
+		SELECT (SELECT * FROM (VALUES (1,2))) IN (SELECT (1), (2), (3));
+	]], {
+		-- <sql-errors-1.57>
+		1, "Unequal number of entries in row expression: left side has 2, but right side - 3"
+		-- </sql-errors-1.57>
+	})
+
+test:do_catchsql_test(
+	"sql-errors-1.58",
+	[[
+		SELECT (SELECT * FROM (VALUES (1,2))) IN (VALUES (1,2,3), (2,3,4));
+	]], {
+		-- <sql-errors-1.58>
+		1, "Unequal number of entries in row expression: left side has 2, but right side - 3"
+		-- </sql-errors-1.58>
+	})
+
+test:do_catchsql_test(
+	"sql-errors-1.59",
+	[[
+		SELECT (SELECT * FROM (VALUES (1,2))) IN (SELECT * from (VALUES (1,2,3), (2,3,4)));
+	]], {
+		-- <sql-errors-1.59>
+		1, "Unequal number of entries in row expression: left side has 2, but right side - 3"
+		-- </sql-errors-1.59>
+	})
+
+test:do_catchsql_test(
+	"sql-errors-1.60",
+	[[
+		SELECT (1,2,3) = (1,2,3);
+	]], {
+		-- <sql-errors-1.60>
+		0, {true}
+		-- </sql-errors-1.60>
+	})
+
+test:do_catchsql_test(
+	"sql-errors-1.61",
+	[[
+		SELECT (1,2) = (1,2,3);
+	]], {
+		-- <sql-errors-1.61>
+		1, "Unequal number of entries in row expression: left side has 2, but right side - 3"
+		-- </sql-errors-1.61>
+	})
+
+test:do_catchsql_test(
+	"sql-errors-1.62",
+	[[
+		SELECT (SELECT (1), (2)) = (1,2,3);
+	]], {
+		-- <sql-errors-1.62>
+		1, "Unequal number of entries in row expression: left side has 2, but right side - 3"
+		-- </sql-errors-1.62>
+	})
+
+test:do_catchsql_test(
+	"sql-errors-1.63",
+	[[
+		SELECT (VALUES (1,2)) = (1,2,3);
+	]], {
+		-- <sql-errors-1.63>
+		1, "Unequal number of entries in row expression: left side has 2, but right side - 3"
+		-- </sql-errors-1.63>
+	})
+
 test:finish_test()
diff --git a/test/sql-tap/subselect.test.lua b/test/sql-tap/subselect.test.lua
index ebfdf431e7577ddbd6010841822a005574006715..3cf87a1bf328915adb71926f15c59049e03f9546 100755
--- a/test/sql-tap/subselect.test.lua
+++ b/test/sql-tap/subselect.test.lua
@@ -49,7 +49,7 @@ test:do_catchsql_test(
         SELECT * FROM t1 WHERE a = (SELECT * FROM t1)
     ]], {
         -- <subselect-1.2>
-        1, "row value misused"
+        1, "Unequal number of entries in row expression: left side has 1, but right side - 2"
         -- </subselect-1.2>
     })