diff --git a/src/box/lua/upgrade.lua b/src/box/lua/upgrade.lua
index 2eb1a4c9a82acbd995381c6537f88379845da5a4..31d24fab2459f02bb4d644b39ef7d5db07274940 100644
--- a/src/box/lua/upgrade.lua
+++ b/src/box/lua/upgrade.lua
@@ -767,7 +767,12 @@ local function upgrade_sequence_to_2_2_1()
         local part = pk[6][1]
         local field = part.field or part[1]
         local path = part.path or ''
-        _space_sequence:update(v[1], {{'!', 4, field}, {'!', 5, path}})
+        local t = _space_sequence:get(v[1])
+        -- Update in-place is banned due to complexity of its
+        -- handling. Delete + insert still work.
+        t = t:update({{'!', 4, field}, {'!', 5, path}})
+        _space_sequence:delete({v[1]})
+        _space_sequence:insert(t)
         ::continue::
     end
     local format = _space_sequence:format()
diff --git a/test/xlog/gh-4771-upgrade.result b/test/xlog/gh-4771-upgrade.result
new file mode 100644
index 0000000000000000000000000000000000000000..032ed993a75b9074fed79d2b2a6c718a15e1f1a4
--- /dev/null
+++ b/test/xlog/gh-4771-upgrade.result
@@ -0,0 +1,78 @@
+-- test-run result file version 2
+test_run = require('test_run').new()
+ | ---
+ | ...
+
+test_run:cmd('create server upgrade with script="xlog/upgrade.lua", '..		\
+             'workdir="xlog/upgrade/2.1.3/gh-4771-upgrade-sequence"')
+ | ---
+ | - true
+ | ...
+test_run:cmd('start server upgrade')
+ | ---
+ | - true
+ | ...
+test_run:switch('upgrade')
+ | ---
+ | - true
+ | ...
+
+box.schema.upgrade()
+ | ---
+ | ...
+
+s = box.space.test1
+ | ---
+ | ...
+box.space._sequence:select{}
+ | ---
+ | - - [1, 1, 'test1_seq', 1, 1, 9223372036854775807, 1, 0, false]
+ |   - [2, 1, 'seq2', 1, 1, 9223372036854775807, 1, 0, false]
+ |   - [3, 1, 'seq3', 1, 1, 9223372036854775807, 1, 0, false]
+ | ...
+box.space._sequence_data:select{}
+ | ---
+ | - - [1, 1]
+ |   - [2, 1]
+ |   - [3, 1]
+ | ...
+box.space._space_sequence:select{}
+ | ---
+ | - - [512, 1, true, 0, '']
+ |   - [513, 2, false, 0, '']
+ | ...
+s:select{}
+ | ---
+ | - - [1]
+ | ...
+_ = s:replace{box.NULL}
+ | ---
+ | ...
+s:select{}
+ | ---
+ | - - [1]
+ |   - [2]
+ | ...
+
+box.space.test2:select{}
+ | ---
+ | - - [1]
+ | ...
+
+box.sequence.seq3:next()
+ | ---
+ | - 2
+ | ...
+
+test_run:switch('default')
+ | ---
+ | - true
+ | ...
+test_run:cmd('stop server upgrade')
+ | ---
+ | - true
+ | ...
+test_run:cmd('delete server upgrade')
+ | ---
+ | - true
+ | ...
diff --git a/test/xlog/gh-4771-upgrade.test.lua b/test/xlog/gh-4771-upgrade.test.lua
new file mode 100644
index 0000000000000000000000000000000000000000..52334404e9d20757995c65d40a4bcd3598d88c15
--- /dev/null
+++ b/test/xlog/gh-4771-upgrade.test.lua
@@ -0,0 +1,24 @@
+test_run = require('test_run').new()
+
+test_run:cmd('create server upgrade with script="xlog/upgrade.lua", '..		\
+             'workdir="xlog/upgrade/2.1.3/gh-4771-upgrade-sequence"')
+test_run:cmd('start server upgrade')
+test_run:switch('upgrade')
+
+box.schema.upgrade()
+
+s = box.space.test1
+box.space._sequence:select{}
+box.space._sequence_data:select{}
+box.space._space_sequence:select{}
+s:select{}
+_ = s:replace{box.NULL}
+s:select{}
+
+box.space.test2:select{}
+
+box.sequence.seq3:next()
+
+test_run:switch('default')
+test_run:cmd('stop server upgrade')
+test_run:cmd('delete server upgrade')
diff --git a/test/xlog/suite.cfg b/test/xlog/suite.cfg
deleted file mode 100644
index c33a80ce9c31a9ddaee6a4fd58c33c6c6f480abc..0000000000000000000000000000000000000000
--- a/test/xlog/suite.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-    "upgrade.test.lua": {
-        "1.7.7": {"version": "1.7.7"}
-    }
-}
diff --git a/test/xlog/suite.ini b/test/xlog/suite.ini
index 689d2b8719a3ec885b53d6ebbb73bfebecdfb57e..635ec53c1607debfea031ecf5f07a2b8ac3219d3 100644
--- a/test/xlog/suite.ini
+++ b/test/xlog/suite.ini
@@ -2,10 +2,9 @@
 core = tarantool
 description = tarantool write ahead log tests
 script = xlog.lua
-disabled = snap_io_rate.test.lua upgrade.test.lua
+disabled = snap_io_rate.test.lua
 valgrind_disabled =
 release_disabled = errinj.test.lua panic_on_lsn_gap.test.lua panic_on_broken_lsn.test.lua checkpoint_threshold.test.lua
-config = suite.cfg
 use_unix_sockets = True
 use_unix_sockets_iproto = True
 long_run = snap_io_rate.test.lua
diff --git a/test/xlog/upgrade.result b/test/xlog/upgrade.result
deleted file mode 100644
index f64b12d7e81bc2a6be430c683ade6de52bbbba9f..0000000000000000000000000000000000000000
--- a/test/xlog/upgrade.result
+++ /dev/null
@@ -1,265 +0,0 @@
-test_run = require('test_run').new()
----
-...
-version = test_run:get_cfg('version')
----
-...
-work_dir = "xlog/upgrade/"..version
----
-...
-test_run:cmd('create server upgrade with script="xlog/upgrade.lua", workdir="'..work_dir..'"')
----
-- true
-...
-test_run:cmd("start server upgrade")
----
-- true
-...
-test_run:switch('upgrade')
----
-- true
-...
-test_run:cmd(string.format("push filter '%s' to '<server_uuid>'", box.info.cluster.uuid))
----
-- true
-...
---
--- Upgrade
---
-box.schema.upgrade()
----
-...
---
--- Migrated data
---
-box.space._schema:select()
----
-- - ['cluster', '<server_uuid>']
-  - ['max_id', 513]
-  - ['version', 2, 1, 0]
-...
-box.space._space:select()
----
-- - [257, 1, '_vinyl_deferred_delete', 'blackhole', 0, {'group_id': 1}, [{'name': 'space_id',
-        'type': 'unsigned'}, {'name': 'lsn', 'type': 'unsigned'}, {'name': 'tuple',
-        'type': 'array'}]]
-  - [272, 1, '_schema', 'memtx', 0, {}, [{'type': 'string', 'name': 'key'}]]
-  - [276, 1, '_collation', 'memtx', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {
-        'name': 'name', 'type': 'string'}, {'name': 'owner', 'type': 'unsigned'},
-      {'name': 'type', 'type': 'string'}, {'name': 'locale', 'type': 'string'}, {
-        'name': 'opts', 'type': 'map'}]]
-  - [280, 1, '_space', 'memtx', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'owner',
-        'type': 'unsigned'}, {'name': 'name', 'type': 'string'}, {'name': 'engine',
-        'type': 'string'}, {'name': 'field_count', 'type': 'unsigned'}, {'name': 'flags',
-        'type': 'map'}, {'name': 'format', 'type': 'array'}]]
-  - [281, 1, '_vspace', 'sysview', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'owner',
-        'type': 'unsigned'}, {'name': 'name', 'type': 'string'}, {'name': 'engine',
-        'type': 'string'}, {'name': 'field_count', 'type': 'unsigned'}, {'name': 'flags',
-        'type': 'map'}, {'name': 'format', 'type': 'array'}]]
-  - [284, 1, '_sequence', 'memtx', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'owner',
-        'type': 'unsigned'}, {'name': 'name', 'type': 'string'}, {'name': 'step',
-        'type': 'integer'}, {'name': 'min', 'type': 'integer'}, {'name': 'max', 'type': 'integer'},
-      {'name': 'start', 'type': 'integer'}, {'name': 'cache', 'type': 'integer'},
-      {'name': 'cycle', 'type': 'boolean'}]]
-  - [285, 1, '_sequence_data', 'memtx', 0, {}, [{'name': 'id', 'type': 'unsigned'},
-      {'name': 'value', 'type': 'integer'}]]
-  - [286, 1, '_vsequence', 'sysview', 0, {}, [{'name': 'id', 'type': 'unsigned'},
-      {'name': 'owner', 'type': 'unsigned'}, {'name': 'name', 'type': 'string'}, {
-        'name': 'step', 'type': 'integer'}, {'name': 'min', 'type': 'integer'}, {
-        'name': 'max', 'type': 'integer'}, {'name': 'start', 'type': 'integer'}, {
-        'name': 'cache', 'type': 'integer'}, {'name': 'cycle', 'type': 'boolean'}]]
-  - [288, 1, '_index', 'memtx', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'iid',
-        'type': 'unsigned'}, {'name': 'name', 'type': 'string'}, {'name': 'type',
-        'type': 'string'}, {'name': 'opts', 'type': 'map'}, {'name': 'parts', 'type': 'array'}]]
-  - [289, 1, '_vindex', 'sysview', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'iid',
-        'type': 'unsigned'}, {'name': 'name', 'type': 'string'}, {'name': 'type',
-        'type': 'string'}, {'name': 'opts', 'type': 'map'}, {'name': 'parts', 'type': 'array'}]]
-  - [296, 1, '_func', 'memtx', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'owner',
-        'type': 'unsigned'}, {'name': 'name', 'type': 'string'}, {'name': 'setuid',
-        'type': 'unsigned'}]]
-  - [297, 1, '_vfunc', 'sysview', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'owner',
-        'type': 'unsigned'}, {'name': 'name', 'type': 'string'}, {'name': 'setuid',
-        'type': 'unsigned'}]]
-  - [304, 1, '_user', 'memtx', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'owner',
-        'type': 'unsigned'}, {'name': 'name', 'type': 'string'}, {'name': 'type',
-        'type': 'string'}, {'name': 'auth', 'type': 'map'}]]
-  - [305, 1, '_vuser', 'sysview', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'owner',
-        'type': 'unsigned'}, {'name': 'name', 'type': 'string'}, {'name': 'type',
-        'type': 'string'}, {'name': 'auth', 'type': 'map'}]]
-  - [312, 1, '_priv', 'memtx', 0, {}, [{'name': 'grantor', 'type': 'unsigned'}, {
-        'name': 'grantee', 'type': 'unsigned'}, {'name': 'object_type', 'type': 'string'},
-      {'name': 'object_id', 'type': 'scalar'}, {'name': 'privilege', 'type': 'unsigned'}]]
-  - [313, 1, '_vpriv', 'sysview', 0, {}, [{'name': 'grantor', 'type': 'unsigned'},
-      {'name': 'grantee', 'type': 'unsigned'}, {'name': 'object_type', 'type': 'string'},
-      {'name': 'object_id', 'type': 'scalar'}, {'name': 'privilege', 'type': 'unsigned'}]]
-  - [320, 1, '_cluster', 'memtx', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'uuid',
-        'type': 'string'}]]
-  - [328, 1, '_trigger', 'memtx', 0, {}, [{'name': 'name', 'type': 'string'}, {'name': 'opts',
-        'type': 'map'}]]
-  - [330, 1, '_truncate', 'memtx', 0, {}, [{'name': 'id', 'type': 'unsigned'}, {'name': 'count',
-        'type': 'unsigned'}]]
-  - [340, 1, '_space_sequence', 'memtx', 0, {}, [{'name': 'id', 'type': 'unsigned'},
-      {'name': 'sequence_id', 'type': 'unsigned'}, {'name': 'is_generated', 'type': 'boolean'}]]
-  - [348, 1, '_sql_stat1', 'memtx', 0, {}, [{'name': 'tbl', 'type': 'string'}, {'name': 'idx',
-        'type': 'string'}, {'name': 'stat', 'type': 'string'}]]
-  - [349, 1, '_sql_stat4', 'memtx', 0, {}, [{'name': 'tbl', 'type': 'string'}, {'name': 'idx',
-        'type': 'string'}, {'name': 'neq', 'type': 'string'}, {'name': 'nlt', 'type': 'string'},
-      {'name': 'ndlt', 'type': 'string'}, {'name': 'sample', 'type': 'scalar'}]]
-  - [512, 1, 'distro', 'memtx', 0, {}, [{'name': 'os', 'type': 'str'}, {'name': 'dist',
-        'type': 'str'}, {'name': 'version', 'type': 'num'}, {'name': 'time', 'type': 'num'}]]
-  - [513, 1, 'temporary', 'memtx', 0, {'temporary': true}, []]
-...
-box.space._index:select()
----
-- - [272, 0, 'primary', 'tree', {'unique': true}, [[0, 'string']]]
-  - [276, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]]
-  - [276, 1, 'name', 'tree', {'unique': true}, [[1, 'string']]]
-  - [280, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]]
-  - [280, 1, 'owner', 'tree', {'unique': false}, [[1, 'unsigned']]]
-  - [280, 2, 'name', 'tree', {'unique': true}, [[2, 'string']]]
-  - [281, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]]
-  - [281, 1, 'owner', 'tree', {'unique': false}, [[1, 'unsigned']]]
-  - [281, 2, 'name', 'tree', {'unique': true}, [[2, 'string']]]
-  - [284, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]]
-  - [284, 1, 'owner', 'tree', {'unique': false}, [[1, 'unsigned']]]
-  - [284, 2, 'name', 'tree', {'unique': true}, [[2, 'string']]]
-  - [285, 0, 'primary', 'hash', {'unique': true}, [[0, 'unsigned']]]
-  - [286, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]]
-  - [286, 1, 'owner', 'tree', {'unique': false}, [[1, 'unsigned']]]
-  - [286, 2, 'name', 'tree', {'unique': true}, [[2, 'string']]]
-  - [288, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned'], [1, 'unsigned']]]
-  - [288, 2, 'name', 'tree', {'unique': true}, [[0, 'unsigned'], [2, 'string']]]
-  - [289, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned'], [1, 'unsigned']]]
-  - [289, 2, 'name', 'tree', {'unique': true}, [[0, 'unsigned'], [2, 'string']]]
-  - [296, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]]
-  - [296, 1, 'owner', 'tree', {'unique': false}, [[1, 'unsigned']]]
-  - [296, 2, 'name', 'tree', {'unique': true}, [[2, 'string']]]
-  - [297, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]]
-  - [297, 1, 'owner', 'tree', {'unique': false}, [[1, 'unsigned']]]
-  - [297, 2, 'name', 'tree', {'unique': true}, [[2, 'string']]]
-  - [304, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]]
-  - [304, 1, 'owner', 'tree', {'unique': false}, [[1, 'unsigned']]]
-  - [304, 2, 'name', 'tree', {'unique': true}, [[2, 'string']]]
-  - [305, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]]
-  - [305, 1, 'owner', 'tree', {'unique': false}, [[1, 'unsigned']]]
-  - [305, 2, 'name', 'tree', {'unique': true}, [[2, 'string']]]
-  - [312, 0, 'primary', 'tree', {'unique': true}, [[1, 'unsigned'], [2, 'string'],
-      [3, 'scalar']]]
-  - [312, 1, 'owner', 'tree', {'unique': false}, [[0, 'unsigned']]]
-  - [312, 2, 'object', 'tree', {'unique': false}, [[2, 'string'], [3, 'scalar']]]
-  - [313, 0, 'primary', 'tree', {'unique': true}, [[1, 'unsigned'], [2, 'string'],
-      [3, 'scalar']]]
-  - [313, 1, 'owner', 'tree', {'unique': false}, [[0, 'unsigned']]]
-  - [313, 2, 'object', 'tree', {'unique': false}, [[2, 'string'], [3, 'scalar']]]
-  - [320, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]]
-  - [320, 1, 'uuid', 'tree', {'unique': true}, [[1, 'string']]]
-  - [328, 0, 'primary', 'tree', {'unique': true}, [[0, 'string']]]
-  - [330, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]]
-  - [340, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]]
-  - [340, 1, 'sequence', 'tree', {'unique': false}, [[1, 'unsigned']]]
-  - [348, 0, 'primary', 'tree', {'unique': true}, [[0, 'string'], [1, 'string']]]
-  - [349, 0, 'primary', 'tree', {'unique': true}, [[0, 'string'], [1, 'string'], [
-        5, 'scalar']]]
-  - [512, 0, 'primary', 'hash', {'unique': true}, [[0, 'string'], [1, 'string'], [
-        2, 'unsigned']]]
-  - [512, 1, 'codename', 'hash', {'unique': true}, [[1, 'string']]]
-  - [512, 2, 'time', 'tree', {'unique': false}, [[3, 'unsigned']]]
-...
-box.space._user:select()
----
-- - [0, 1, 'guest', 'user', {'chap-sha1': 'vhvewKp0tNyweZQ+cFKAlsyphfg='}]
-  - [1, 1, 'admin', 'user', {}]
-  - [2, 1, 'public', 'role', {}]
-  - [3, 1, 'replication', 'role', {}]
-  - [31, 1, 'super', 'role', {}]
-  - [32, 1, 'someuser', 'user', {'chap-sha1': '2qvbQIHM4zMWhAmm2xGeGNjqoHM='}]
-  - [33, 1, 'somerole', 'role', {}]
-...
-box.space._func:select()
----
-- - [1, 1, 'box.schema.user.info', 1, 'LUA']
-  - [2, 32, 'somefunc', 1, 'LUA']
-  - [3, 1, 'someotherfunc', 0, 'LUA']
-...
-box.space._collation:select()
----
-- - [1, 'unicode', 1, 'ICU', '', {}]
-  - [2, 'unicode_ci', 1, 'ICU', '', {'strength': 'primary'}]
-...
-box.space._priv:select()
----
-- - [1, 0, 'role', 2, 4]
-  - [1, 0, 'universe', 0, 24]
-  - [1, 1, 'universe', 0, 4294967295]
-  - [1, 2, 'function', 1, 4]
-  - [1, 2, 'function', 2, 4]
-  - [1, 2, 'space', 276, 2]
-  - [1, 2, 'space', 281, 1]
-  - [1, 2, 'space', 286, 1]
-  - [1, 2, 'space', 289, 1]
-  - [1, 2, 'space', 297, 1]
-  - [1, 2, 'space', 305, 1]
-  - [1, 2, 'space', 313, 1]
-  - [1, 2, 'space', 330, 2]
-  - [1, 3, 'space', 320, 2]
-  - [1, 3, 'universe', 0, 1]
-  - [1, 31, 'universe', 0, 4294967295]
-  - [1, 32, 'function', 3, 4]
-  - [1, 32, 'role', 2, 4]
-  - [1, 32, 'role', 33, 4]
-  - [1, 32, 'space', 513, 3]
-  - [1, 32, 'universe', 0, 24]
-  - [1, 33, 'space', 512, 3]
-...
-box.space._vspace ~= nil
----
-- true
-...
-box.space._vindex ~= nil
----
-- true
-...
-box.space._vuser ~= nil
----
-- true
-...
-box.space._vpriv ~= nil
----
-- true
-...
--- a test space
-r = box.space.distro:select()
----
-...
-_ = table.sort(r, function(left, right) return tostring(left) < tostring(right) end)
----
-...
-r
----
-- - ['debian', 'etch', 40, 1176019200]
-  - ['debian', 'jessie', 80, 1430038800]
-  - ['debian', 'lenny', 50, 1234602000]
-  - ['debian', 'sarge', 31, 1118044800]
-  - ['debian', 'squeeze', 60, 1296896400]
-  - ['debian', 'wheezy', 70, 1367654400]
-  - ['debian', 'woody', 30, 1027065600]
-  - ['ubuntu', 'precise', 1510, 1335427200]
-  - ['ubuntu', 'trusty', 1404, 1397721600]
-  - ['ubuntu', 'vivid', 1504, 1429779600]
-  - ['ubuntu', 'wily', 1510, 1445504400]
-...
-test_run:cmd("clear filter")
----
-- true
-...
-test_run:switch('default')
----
-- true
-...
-test_run:cmd('stop server upgrade')
----
-- true
-...
-test_run = nil
----
-...
diff --git a/test/xlog/upgrade.test.lua b/test/xlog/upgrade.test.lua
deleted file mode 100644
index 0be2d34e95f543197069363614372c5a5d05c53d..0000000000000000000000000000000000000000
--- a/test/xlog/upgrade.test.lua
+++ /dev/null
@@ -1,46 +0,0 @@
-test_run = require('test_run').new()
-
-version = test_run:get_cfg('version')
-work_dir = "xlog/upgrade/"..version
-
-test_run:cmd('create server upgrade with script="xlog/upgrade.lua", workdir="'..work_dir..'"')
-test_run:cmd("start server upgrade")
-
-test_run:switch('upgrade')
-
-test_run:cmd(string.format("push filter '%s' to '<server_uuid>'", box.info.cluster.uuid))
-
---
--- Upgrade
---
-
-box.schema.upgrade()
-
---
--- Migrated data
---
-
-box.space._schema:select()
-box.space._space:select()
-box.space._index:select()
-box.space._user:select()
-box.space._func:select()
-box.space._collation:select()
-box.space._priv:select()
-
-box.space._vspace ~= nil
-box.space._vindex ~= nil
-box.space._vuser ~= nil
-box.space._vpriv ~= nil
-
--- a test space
-r = box.space.distro:select()
-_ = table.sort(r, function(left, right) return tostring(left) < tostring(right) end)
-r
-
-test_run:cmd("clear filter")
-
-test_run:switch('default')
-test_run:cmd('stop server upgrade')
-
-test_run = nil
diff --git a/test/xlog/upgrade/2.1.3/gh-4771-upgrade-sequence/00000000000000000014.snap b/test/xlog/upgrade/2.1.3/gh-4771-upgrade-sequence/00000000000000000014.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c0d2ef404c4e54377230a3134394dbc7abb5f730
Binary files /dev/null and b/test/xlog/upgrade/2.1.3/gh-4771-upgrade-sequence/00000000000000000014.snap differ
diff --git a/test/xlog/upgrade/2.1.3/gh-4771-upgrade-sequence/fill.lua b/test/xlog/upgrade/2.1.3/gh-4771-upgrade-sequence/fill.lua
new file mode 100644
index 0000000000000000000000000000000000000000..b159f2b6708d67eb52238cfacd95400b740d54f4
--- /dev/null
+++ b/test/xlog/upgrade/2.1.3/gh-4771-upgrade-sequence/fill.lua
@@ -0,0 +1,14 @@
+box.cfg{}
+s1 = box.schema.create_space('test1')
+pk = s1:create_index('pk', {sequence = true})
+s1:replace{box.NULL}
+
+seq2 = box.schema.sequence.create('seq2')
+s2 = box.schema.create_space('test2')
+pk = s2:create_index('pk', {sequence = 'seq2'})
+s2:replace{box.NULL}
+
+seq3 = box.schema.sequence.create('seq3')
+seq3:next()
+
+box.snapshot()
diff --git a/test/xlog/upgrade/how_to_add_new_test.md b/test/xlog/upgrade/how_to_add_new_test.md
new file mode 100644
index 0000000000000000000000000000000000000000..3fa3c2d447d43eaac55427ca48f3d883ebb640f1
--- /dev/null
+++ b/test/xlog/upgrade/how_to_add_new_test.md
@@ -0,0 +1,36 @@
+## How to add a new upgrade test
+
+Firstly, for a new test should be prepared a `fill.lua` file. Here
+should be code to populate needed spaces, create xlogs, snapshots.
+
+`Fill.lua` should be run in an old Tarantool version, upgrade from
+which is going to be tested. This will produce `.xlog` and `.snap`
+files. They should be saved into
+`xlog/upgrade/<version>/<test_name>/` folder. Snapshot is usually
+enough. Version is the old Tarantool version. Test name is a name
+of test file, which will test recovery from these xlogs. It should
+obey to the same rules as other test file names.
+
+Secondly, it is necessary to add a `<test_name>.test.lua` file to
+`xlog/` folder, to all the other tests. It should start a new
+instance of Tarantool with workdir set to
+`xlog/upgrade/<version>/<test_name>/`. Then this file should
+ensure, that `box.upgrade()` works fine, and all data is recovered
+correctly.
+
+The following directory structure should be in the result:
+```
+ xlog/
+ |
+ +- <test_name>.test.lua
+ |
+ +- upgrade/
+    |
+    +- <version>/
+        |
+        +- <test_name>/
+           |
+           +- fill.lua
+           +- *.snap
+           +- *.xlog
+```