diff --git a/doc/sphinx/book/box/box_index.rst b/doc/sphinx/book/box/box_index.rst
index 46967180ec9ca3e1754518f03613bb262478c4d3..4c07a6134e8ffbf7286bce03b9a58740d705780b 100644
--- a/doc/sphinx/book/box/box_index.rst
+++ b/doc/sphinx/book/box/box_index.rst
@@ -470,6 +470,33 @@ API is a direct binding to corresponding methods of index objects of type
         | :codenormal:`- 1`
         | :codenormal:`...`
 
+    .. function:: update(key, {{operator, field_no, value}, ...})
+
+        Update a tuple.
+
+        Same as :func:`box.space...update() <space_object.update>`,
+        but key is searched in this index instead of primary key.
+        This index ought to be unique.
+
+        :param lua-value key: key to be matched against the index key
+        :param table {operator, field_no, value}: update opearations (see: func:`box.space...update() <space_object.update>`)
+
+        :return: the updated tuple.
+        :rtype:  tuple
+
+    .. function:: delete(key)
+
+        Delete a tuple identified by a key.
+
+        Same as :func:`box.space...delete() <space_object.delete>`,
+        but key is searched in this index instead of primary key.
+        This index ought to be unique.
+
+        :param lua-value key: key to be matched against the index key
+
+        :return: the deleted tuple.
+        :rtype:  tuple
+
     .. function:: alter({options})
 
         Alter an index.
diff --git a/src/box/request.cc b/src/box/request.cc
index 719d76bdcdae272f5a7359a5d8e59cf4d139247d..57321ed88b840d72dff13e593bba195a536bde4d 100644
--- a/src/box/request.cc
+++ b/src/box/request.cc
@@ -80,8 +80,10 @@ execute_update(struct request *request, struct port *port)
 	struct txn *txn = txn_begin_stmt(request, space);
 
 	access_check_space(space, PRIV_W);
-	Index *pk = index_find(space, 0);
-	/* Try to find the tuple by primary key. */
+	/* Try to find the tuple by unique key. */
+	Index *pk = index_find(space, request->index_id);
+	if (!pk->key_def->is_unique)
+		tnt_raise(ClientError, ER_MORE_THAN_ONE_TUPLE);
 	const char *key = request->key;
 	uint32_t part_count = mp_decode_array(&key);
 	primary_key_validate(pk->key_def, key, part_count);
@@ -122,8 +124,10 @@ execute_delete(struct request *request, struct port *port)
 
 	access_check_space(space, PRIV_W);
 
-	/* Try to find tuple by primary key */
-	Index *pk = index_find(space, 0);
+	/* Try to find the tuple by unique key. */
+	Index *pk = index_find(space, request->index_id);
+	if (!pk->key_def->is_unique)
+		tnt_raise(ClientError, ER_MORE_THAN_ONE_TUPLE);
 	const char *key = request->key;
 	uint32_t part_count = mp_decode_array(&key);
 	primary_key_validate(pk->key_def, key, part_count);
diff --git a/src/lua/net_box.lua b/src/lua/net_box.lua
index 6f4231dc4193afd9d2505dd29b3d5ef73985e4a3..1c6e99ec2dadca5ba8e297c4af6fa730f00f3cae 100644
--- a/src/lua/net_box.lua
+++ b/src/lua/net_box.lua
@@ -157,19 +157,19 @@ local proto = {
     end,
 
     -- delete
-    delete = function(sync, spaceno, key)
+    delete = function(sync, spaceno, key, index_id)
         return request(
             { [SYNC] = sync, [TYPE] = DELETE },
-            { [SPACE_ID] = spaceno, [KEY] = keyfy(key) }
+            { [SPACE_ID] = spaceno, [INDEX_ID] = index_id, [KEY] = keyfy(key) }
         )
     end,
 
     -- update
-    update = function(sync, spaceno, key, oplist)
+    update = function(sync, spaceno, key, oplist, index_id)
         return request(
             { [SYNC] = sync, [TYPE] = UPDATE },
             { [KEY] = keyfy(key), [INDEX_BASE] = 1 , [TUPLE]  = oplist,
-              [SPACE_ID] = spaceno }
+              [SPACE_ID] = spaceno, [INDEX_ID] = index_id }
         )
     end,
 
@@ -256,12 +256,12 @@ local function space_metatable(self)
 
             delete = function(space, key)
                 check_if_space(space)
-                return self:_delete(space.id, key)
+                return self:_delete(space.id, key, 0)
             end,
 
             update = function(space, key, oplist)
                 check_if_space(space)
-                return self:_update(space.id, key, oplist)
+                return self:_update(space.id, key, oplist, 0)
             end,
 
             get = function(space, key)
@@ -334,7 +334,18 @@ local function index_metatable(self)
                 if #res > 0 then
                     return res[1][1]
                 end
-            end
+            end,
+
+            delete = function(idx, key)
+                check_if_index(idx)
+                return self:_delete(idx.space.id, key, idx.id)
+            end,
+
+            update = function(idx, key, oplist)
+                check_if_index(idx)
+                return self:_update(idx.space.id, key, oplist, idx.id)
+            end,
+
         }
     }
 end
@@ -1041,13 +1052,13 @@ local remote_methods = {
         return one_tuple(res.body[DATA])
     end,
 
-    _delete  = function(self, spaceno, key)
-        local res = self:_request('delete', true, spaceno, key)
+    _delete  = function(self, spaceno, key, index_id)
+        local res = self:_request('delete', true, spaceno, key, index_id)
         return one_tuple(res.body[DATA])
     end,
 
-    _update = function(self, spaceno, key, oplist)
-        local res = self:_request('update', true, spaceno, key, oplist)
+    _update = function(self, spaceno, key, oplist, index_id)
+        local res = self:_request('update', true, spaceno, key, oplist, index_id)
         return one_tuple(res.body[DATA])
     end
 }
diff --git a/test/box/sql.result b/test/box/sql.result
index 4c48ce6ba5420205c4cb5a970639f786d0ba64f3..19eddef048b3a48ec5ce47db9a9686643cbc372f 100644
--- a/test/box/sql.result
+++ b/test/box/sql.result
@@ -4,6 +4,9 @@ net_box = require('net.box')
 s = box.schema.space.create('test', { id = 0 })
 ---
 ...
+_ = box.schema.space.create('test1', { id = 555 })
+---
+...
 box.schema.user.create('test', { password = 'test' })
 ---
 ...
@@ -19,6 +22,12 @@ space = conn.space.test
 index = box.space.test:create_index('primary', { type = 'hash' })
 ---
 ...
+_ = box.space.test1:create_index('primary', { type = 'hash' })
+---
+...
+_ = box.space.test1:create_index('secondary', { type = 'hash', parts = {2, 'str'}})
+---
+...
 conn:ping()
 ---
 - true
@@ -178,6 +187,19 @@ space:select{4294967295}
 ---
 - []
 ...
+-- check update delete be secondary index
+conn.space.test1:insert{0, "hello", 1}
+---
+- [0, 'hello', 1]
+...
+conn.space.test1.index.secondary:update("hello", {{'=', 3, 2}})
+---
+- [0, 'hello', 2]
+...
+conn.space.test1.index.secondary:delete("hello")
+---
+- [0, 'hello', 2]
+...
 -- cleanup 
 space:delete(0)
 ---
@@ -189,6 +211,9 @@ space:delete(4294967295)
 box.space.test:drop()
 ---
 ...
+box.space.test1:drop()
+---
+...
 box.schema.user.drop('test')
 ---
 ...
diff --git a/test/box/sql.test.lua b/test/box/sql.test.lua
index ba9240ba537f61e1eeadb5d747f926c88a39cdbe..bad89b7c2b87cf6b1f13ec592731610cf8d68dc9 100644
--- a/test/box/sql.test.lua
+++ b/test/box/sql.test.lua
@@ -1,6 +1,7 @@
 net_box = require('net.box')
 
 s = box.schema.space.create('test', { id = 0 })
+_ = box.schema.space.create('test1', { id = 555 })
 box.schema.user.create('test', { password = 'test' })
 box.schema.user.grant('test', 'execute,read,write', 'universe')
 
@@ -8,6 +9,8 @@ conn = net_box:new('test:test@' .. box.cfg.listen)
 space = conn.space.test
 
 index = box.space.test:create_index('primary', { type = 'hash' })
+_ = box.space.test1:create_index('primary', { type = 'hash' })
+_ = box.space.test1:create_index('secondary', { type = 'hash', parts = {2, 'str'}})
 conn:ping()
 
 -- xxx: bug  currently selects no rows
@@ -72,9 +75,15 @@ space:insert{0}
 space:select{0}
 space:select{4294967295}
 
+-- check update delete be secondary index
+conn.space.test1:insert{0, "hello", 1}
+conn.space.test1.index.secondary:update("hello", {{'=', 3, 2}})
+conn.space.test1.index.secondary:delete("hello")
+
 -- cleanup 
 space:delete(0)
 space:delete(4294967295)
 box.space.test:drop()
+box.space.test1:drop()
 box.schema.user.drop('test')
 space = nil