diff --git a/test/box/protocol.result b/test/box/protocol.result
index cbeedabbc341a75a98e00694aa59de19cfa553f0..07366ba5a901c426145f9f3bd06b67ed8b31f6a9 100644
--- a/test/box/protocol.result
+++ b/test/box/protocol.result
@@ -1,3 +1,5 @@
 return_code: 0
 return_code: ER_ILLEGAL_PARAMS, Illegal parameters, tuple count must be positive
 return_code: ER_NO_SUCH_INDEX, No index #1 is defined in space 0
+delete from t0 where k0 = 1
+Delete OK, 1 row affected
diff --git a/test/box/protocol.test b/test/box/protocol.test
index e70396105a7c9a24395e264867906773070faa5c..9c7db26a20aa7b90088d6978eea0e399c4ef02f4 100644
--- a/test/box/protocol.test
+++ b/test/box/protocol.test
@@ -1,3 +1,5 @@
+# encoding: tarantool
+#
 import subprocess
 import sys
 import os
@@ -7,3 +9,6 @@ p = subprocess.Popen([ os.path.join(builddir, "test/box/protocol") ],
 p.wait()
 for line in p.stdout.readlines():
       sys.stdout.write(line)
+
+exec sql "delete from t0 where k0 = 1"
+# vim: syntax=python
diff --git a/test/box/sql.result b/test/box/sql.result
index 7bf86c60510e7fb5f308324af097584dca812123..9c298c7efc77e96b64e9480749fdfc89f6f99862 100644
--- a/test/box/sql.result
+++ b/test/box/sql.result
@@ -53,8 +53,8 @@ An error occurred: ER_NO_SUCH_FIELD, 'Field 1000 was not found in the tuple'
 select * from t0 where k0 = 1
 Found 1 tuple:
 [1, 'Huh', 'I am a new field! I was added via append']
-insert into t0 values (1, 'I am a new tuple', 'stub')
-Insert OK, 1 row affected
+replace into t0 values (1, 'I am a new tuple', 'stub')
+Replace OK, 1 row affected
 update t0 set k1 = 'Huh', k2 = 'Oh-ho-ho' where k0=1
 Update OK, 1 row affected
 select * from t0 where k0 = 1
diff --git a/test/box/sql.test b/test/box/sql.test
index 28eec05198da3ffbf7004f7d98ddfb1aecdb3c7a..f950f5da8de6dfa4b835211c3f4004d07c9722a5 100644
--- a/test/box/sql.test
+++ b/test/box/sql.test
@@ -30,7 +30,7 @@ exec sql "select * from t0 where k0 = 1"
 # this is illegal
 exec sql "update t0 set k1 = 'Huh', k1000 = 'invalid field' where k0=1"
 exec sql "select * from t0 where k0 = 1"
-exec sql "insert into t0 values (1, 'I am a new tuple', 'stub')"
+exec sql "replace into t0 values (1, 'I am a new tuple', 'stub')"
 exec sql "update t0 set k1 = 'Huh', k2 = 'Oh-ho-ho' where k0=1"
 exec sql "select * from t0 where k0 = 1"
 # check empty strings
diff --git a/test/box_big/sql.result b/test/box_big/sql.result
index bc16af0b073b6df9d862ee27617f08d3168bcf0c..0edcb14011b7e64e427d69870a6defcec0669dfe 100644
--- a/test/box_big/sql.result
+++ b/test/box_big/sql.result
@@ -76,8 +76,8 @@ Delete OK, 1 row affected
 #
 insert into t1 values ('key1', 'part1', 'part2')
 Insert OK, 1 row affected
-insert into t1 values ('key1', 'part1', 'part2')
-Insert OK, 1 row affected
+replace into t1 values ('key1', 'part1', 'part2')
+Replace OK, 1 row affected
 insert into t1 values ('key2', 'part1', 'part2_a')
 Insert OK, 1 row affected
 insert into t1 values ('key3', 'part1', 'part2_b')
@@ -241,7 +241,7 @@ Found 1 tuple:
 select * from t4 where k1='Britney'
 Found 1 tuple:
 ['Spears', 'Britney']
-insert into t4 values ('Spears')
+replace into t4 values ('Spears')
 An error occurred: ER_ILLEGAL_PARAMS, 'Illegal parameters, tuple must have all indexed fields'
 select * from t4 where k0='Spears'
 Found 1 tuple:
diff --git a/test/box_big/sql.test b/test/box_big/sql.test
index 20839b4ec8b379002afba601a5638104bf9ba6b5..1ebf223dfc5f979a1cb9dc1d054aed9e3dfdcccd 100644
--- a/test/box_big/sql.test
+++ b/test/box_big/sql.test
@@ -53,7 +53,7 @@ print """#
 #"""
 exec sql "insert into t1 values ('key1', 'part1', 'part2')"
 # Test a duplicate insert on unique index that once resulted in a crash (bug #926080)
-exec sql "insert into t1 values ('key1', 'part1', 'part2')"
+exec sql "replace into t1 values ('key1', 'part1', 'part2')"
 exec sql "insert into t1 values ('key2', 'part1', 'part2_a')"
 exec sql "insert into t1 values ('key3', 'part1', 'part2_b')"
 exec admin "lua for k, v in box.space[1]:pairs() do print(v) end"
@@ -125,7 +125,7 @@ exec sql "insert into t4 values ('Spears', 'Britney')"
 exec sql "select * from t4 where k0='Spears'"
 exec sql "select * from t4 where k1='Britney'"
 # try to insert the incoplete tuple
-exec sql "insert into t4 values ('Spears')"
+exec sql "replace into t4 values ('Spears')"
 # check that nothing has been updated
 exec sql "select * from t4 where k0='Spears'"
 # cleanup
diff --git a/test/lib/sql.g b/test/lib/sql.g
index 2e41965d5681285c6626438bb1c80f1bb41efa4e..4a15ba41bf713441a0231ad1bb5986c5cbc3a92f 100644
--- a/test/lib/sql.g
+++ b/test/lib/sql.g
@@ -18,6 +18,7 @@ parser sql:
     token STR:        '\'([^\']+|\\\\.)*\''
     token PING:       'ping'
     token INSERT:     'insert'
+    token REPLACE:    'replace'
     token UPDATE:     'update'
     token DELETE:     'delete'
     token SELECT:     'select'
@@ -32,6 +33,7 @@ parser sql:
     token END:        '\\s*$'
 
     rule sql:         (insert {{ stmt = insert }} |
+                      replace {{ stmt = replace }} |
                       update {{ stmt = update }} |
                       delete {{ stmt = delete }} |
                       select {{ stmt = select }} |
@@ -40,6 +42,8 @@ parser sql:
                       
     rule insert:      INSERT [INTO] ident VALUES value_list
                       {{ return sql_ast.StatementInsert(ident, value_list) }}
+    rule replace:     REPLACE [INTO] ident VALUES value_list
+                      {{ return sql_ast.StatementReplace(ident, value_list) }}
     rule update:      UPDATE ident SET update_list opt_simple_where
                       {{ return sql_ast.StatementUpdate(ident, update_list, opt_simple_where) }}
     rule delete:      DELETE FROM ident opt_simple_where
diff --git a/test/lib/sql.py b/test/lib/sql.py
index ad5b92331629c14eea1e855c43480b60d9b64a1b..e8cdb062953b418d543301376c8ec6a36339bdbc 100644
--- a/test/lib/sql.py
+++ b/test/lib/sql.py
@@ -23,6 +23,7 @@ class sqlScanner(runtime.Scanner):
         ('STR', re.compile("'([^']+|\\\\.)*'")),
         ('PING', re.compile('ping')),
         ('INSERT', re.compile('insert')),
+        ('REPLACE', re.compile('replace')),
         ('UPDATE', re.compile('update')),
         ('DELETE', re.compile('delete')),
         ('SELECT', re.compile('select')),
@@ -43,10 +44,13 @@ class sql(runtime.Parser):
     Context = runtime.Context
     def sql(self, _parent=None):
         _context = self.Context(_parent, self._scanner, 'sql', [])
-        _token = self._peek('INSERT', 'UPDATE', 'DELETE', 'SELECT', 'CALL', 'PING', context=_context)
+        _token = self._peek('INSERT', 'REPLACE', 'UPDATE', 'DELETE', 'SELECT', 'CALL', 'PING', context=_context)
         if _token == 'INSERT':
             insert = self.insert(_context)
             stmt = insert
+        elif _token == 'REPLACE':
+            replace = self.replace(_context)
+            stmt = replace
         elif _token == 'UPDATE':
             update = self.update(_context)
             stmt = update
@@ -75,6 +79,16 @@ class sql(runtime.Parser):
         value_list = self.value_list(_context)
         return sql_ast.StatementInsert(ident, value_list)
 
+    def replace(self, _parent=None):
+        _context = self.Context(_parent, self._scanner, 'replace', [])
+        REPLACE = self._scan('REPLACE', context=_context)
+        if self._peek('INTO', 'ID', context=_context) == 'INTO':
+            INTO = self._scan('INTO', context=_context)
+        ident = self.ident(_context)
+        VALUES = self._scan('VALUES', context=_context)
+        value_list = self.value_list(_context)
+        return sql_ast.StatementReplace(ident, value_list)
+
     def update(self, _parent=None):
         _context = self.Context(_parent, self._scanner, 'update', [])
         UPDATE = self._scan('UPDATE', context=_context)
diff --git a/test/lib/sql_ast.py b/test/lib/sql_ast.py
index 71fa7723917964a5a769f2239cc1883f8a9d519a..0f353dfb17088f39f8a9a86a517f8ac917d75a1d 100644
--- a/test/lib/sql_ast.py
+++ b/test/lib/sql_ast.py
@@ -210,7 +210,7 @@ class StatementInsert(StatementPing):
 
     def __init__(self, table_name, value_list):
         self.space_no = table_name
-        self.flags = 0
+        self.flags = 0x02 # ADD
         self.value_list = value_list
 
     def pack(self):
@@ -226,6 +226,26 @@ class StatementInsert(StatementPing):
         (tuple_count,) = struct.unpack("<L", response[4:8])
         return "Insert OK, {0} row affected".format(tuple_count)
 
+class StatementReplace(StatementPing):
+    reqeust_type = INSERT_REQUEST_TYPE
+
+    def __init__(self, table_name, value_list):
+        self.space_no = table_name
+        self.flags = 0x04 # REPLACE
+        self.value_list = value_list
+
+    def pack(self):
+        buf = ctypes.create_string_buffer(PACKET_BUF_LEN)
+        (buf, offset) = pack_tuple(self.value_list, buf, INSERT_REQUEST_FIXED_LEN)
+        struct.pack_into("<LL", buf, 0, self.space_no, self.flags)
+        return buf[:offset]
+
+    def unpack(self, response):
+        (return_code,) = struct.unpack("<L", response[:4])
+        if return_code:
+            return format_error(return_code, response)
+        (tuple_count,) = struct.unpack("<L", response[4:8])
+        return "Replace OK, {0} row affected".format(tuple_count)
 
 class StatementUpdate(StatementPing):
     reqeust_type = UPDATE_REQUEST_TYPE