diff --git a/changelogs/unreleased/gh-4717-binding-for-decimal.md b/changelogs/unreleased/gh-4717-binding-for-decimal.md
new file mode 100644
index 0000000000000000000000000000000000000000..3612e287d801801d535e5d780293e7741ecbf512
--- /dev/null
+++ b/changelogs/unreleased/gh-4717-binding-for-decimal.md
@@ -0,0 +1,3 @@
+## feature/sql
+
+* Now DECIMAL values can be bound in SQL (gh-4717).
diff --git a/src/box/bind.c b/src/box/bind.c
index 734f6518631593e5c07ed6020d51ecf5ac04f0c9..58fff0b98731ce7ef1cee4b6d90e4626a2301e1b 100644
--- a/src/box/bind.c
+++ b/src/box/bind.c
@@ -192,8 +192,10 @@ sql_bind_column(struct sql_stmt *stmt, const struct sql_bind *p,
 		return sql_bind_blob64(stmt, pos, (const void *) p->s, p->bytes,
 				       SQL_STATIC);
 	case MP_EXT:
-		assert(p->ext_type == MP_UUID);
-		return sql_bind_uuid(stmt, pos, &p->uuid);
+		assert(p->ext_type == MP_UUID || p->ext_type == MP_DECIMAL);
+		if (p->ext_type == MP_UUID)
+			return sql_bind_uuid(stmt, pos, &p->uuid);
+		return sql_bind_dec(stmt, pos, &p->dec);
 	default:
 		unreachable();
 	}
diff --git a/src/box/bind.h b/src/box/bind.h
index 143f010cedfc22ca425540564975c753945fb676..1ab8ea72d0b0726c114ece38ca8263dc44dda0da 100644
--- a/src/box/bind.h
+++ b/src/box/bind.h
@@ -40,6 +40,7 @@ extern "C" {
 #include <stdlib.h>
 
 #include "msgpuck.h"
+#include "decimal.h"
 #include "uuid/tt_uuid.h"
 #include "mp_extension_types.h"
 
@@ -72,6 +73,7 @@ struct sql_bind {
 		/** For string or blob. */
 		const char *s;
 		struct tt_uuid uuid;
+		decimal_t dec;
 	};
 };
 
diff --git a/src/box/lua/execute.c b/src/box/lua/execute.c
index 62ccaf3f143f6e89f9196a54d9e1234d19d54447..777db82cb6e188342286d4d36ecc42e424701f7f 100644
--- a/src/box/lua/execute.c
+++ b/src/box/lua/execute.c
@@ -375,6 +375,10 @@ lua_sql_bind_decode(struct lua_State *L, struct sql_bind *bind, int idx, int i)
 			bind->uuid = *field.uuidval;
 			break;
 		}
+		if (field.ext_type == MP_DECIMAL) {
+			bind->dec = *field.decval;
+			break;
+		}
 		diag_set(ClientError, ER_SQL_BIND_TYPE, "USERDATA",
 			 sql_bind_name(bind));
 		return -1;
diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c
index 4c40f15dc3f9a39ebf76f7ec07387fc350c6af16..24de26548f29f2b3daaabb96d4467e9e8aefa986 100644
--- a/src/box/sql/mem.c
+++ b/src/box/sql/mem.c
@@ -293,7 +293,7 @@ mem_set_double(struct Mem *mem, double value)
 }
 
 void
-mem_set_dec(struct Mem *mem, decimal_t *d)
+mem_set_dec(struct Mem *mem, const decimal_t *d)
 {
 	mem_clear(mem);
 	mem->u.d = *d;
diff --git a/src/box/sql/mem.h b/src/box/sql/mem.h
index 543944b804fb7ec7665e4d3c9b1284e868e6a14f..0da45b8af505c6162cdaf31280efdfd54dbfc526 100644
--- a/src/box/sql/mem.h
+++ b/src/box/sql/mem.h
@@ -312,7 +312,7 @@ mem_set_uuid(struct Mem *mem, const struct tt_uuid *uuid);
 
 /** Clear MEM and set it to DECIMAL. */
 void
-mem_set_dec(struct Mem *mem, decimal_t *dec);
+mem_set_dec(struct Mem *mem, const decimal_t *dec);
 
 /** Clear MEM and set it to STRING. The string belongs to another object. */
 void
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index d78076868d2d1272108dd638b1dd3396f83fc91d..2e250dc29170f8a70fe1977895ed06823aa4aa20 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -76,6 +76,8 @@
 #include "box/txn.h"
 #include "trivia/util.h"
 
+#include "decimal.h"
+
 /*
  * These #defines should enable >2GB file support on POSIX if the
  * underlying operating system supports it.  If the OS lacks
@@ -639,6 +641,9 @@ sql_bind_zeroblob64(sql_stmt *, int,
 int
 sql_bind_uuid(struct sql_stmt *stmt, int i, const struct tt_uuid *uuid);
 
+int
+sql_bind_dec(struct sql_stmt *stmt, int i, const decimal_t *dec);
+
 /**
  * Return the number of wildcards that should be bound to.
  */
diff --git a/src/box/sql/vdbeapi.c b/src/box/sql/vdbeapi.c
index 8031ee0dc1071a9b6133c48247910200b8435969..77df0e4cc2f8749206eec3733bc38dc97ce16788 100644
--- a/src/box/sql/vdbeapi.c
+++ b/src/box/sql/vdbeapi.c
@@ -850,6 +850,16 @@ sql_bind_uuid(struct sql_stmt *stmt, int i, const struct tt_uuid *uuid)
 	return 0;
 }
 
+int
+sql_bind_dec(struct sql_stmt *stmt, int i, const decimal_t *dec)
+{
+	struct Vdbe *p = (struct Vdbe *)stmt;
+	if (vdbeUnbind(p, i) != 0 || sql_bind_type(p, i, "decimal") != 0)
+		return -1;
+	mem_set_dec(&p->aVar[i - 1], dec);
+	return 0;
+}
+
 int
 sql_bind_parameter_count(const struct sql_stmt *stmt)
 {
diff --git a/test/sql-tap/decimal.test.lua b/test/sql-tap/decimal.test.lua
index 69288d696ef1b58d7c20c5c132ab4041375f13fa..d422533d692f1a7a2fcd14a4ea795eff51d1f638 100755
--- a/test/sql-tap/decimal.test.lua
+++ b/test/sql-tap/decimal.test.lua
@@ -3,7 +3,7 @@ local build_path = os.getenv("BUILDDIR")
 package.cpath = build_path..'/test/sql-tap/?.so;'..build_path..'/test/sql-tap/?.dylib;'..package.cpath
 
 local test = require("sqltester")
-test:plan(101)
+test:plan(104)
 
 local dec = require("decimal")
 local dec1 = dec.new("111")
@@ -938,6 +938,27 @@ test:do_catchsql_test(
         1, "Inconsistent types: expected string or varbinary got decimal(111)"
     })
 
+-- Make sure that DECIMAL value can be bound.
+test:do_test(
+    "dec-16-1",
+    function()
+        return box.execute([[SELECT ?;]], {dec1}).rows[1][1]
+    end,
+    dec1)
+test:do_test(
+    "dec-16-2",
+    function()
+        return box.execute([[SELECT $2;]], {123, dec2}).rows[1][1]
+    end,
+    dec2)
+
+test:do_test(
+    "dec-16-3",
+    function()
+        return box.execute([[SELECT :two;]], {{[":two"] = dec3}}).rows[1][1]
+    end,
+    dec3)
+
 test:execsql([[
     DROP TRIGGER t;
     DROP VIEW v;