diff --git a/mysql-test/suite/versioning/common.inc b/mysql-test/suite/versioning/common.inc
index f296b631f94..3f508f9baf2 100644
--- a/mysql-test/suite/versioning/common.inc
+++ b/mysql-test/suite/versioning/common.inc
@@ -43,6 +43,18 @@ begin
   return NULL;
 end~~
 
+create function if not exists current_row(sys_trx_end varbinary(255))
+returns int
+deterministic
+begin
+  if default_engine() = 'innodb' then
+    return sys_trx_end = 18446744073709551615;
+  elseif default_engine() = 'myisam' then
+    return sys_trx_end = timestamp'2038-01-19 03:14:07.999999';
+  end if;
+  return NULL;
+end~~
+
 create function if not exists sys_commit_ts(sys_field varchar(255))
 returns varchar(255)
 deterministic
diff --git a/mysql-test/suite/versioning/common_finish.inc b/mysql-test/suite/versioning/common_finish.inc
index 3113c01af2e..ede6bd4ba0c 100644
--- a/mysql-test/suite/versioning/common_finish.inc
+++ b/mysql-test/suite/versioning/common_finish.inc
@@ -4,6 +4,7 @@ drop procedure innodb_verify_vtq;
 drop function default_engine;
 drop function sys_commit_ts;
 drop function sys_datatype;
+drop function current_row;
 drop procedure concat_exec2;
 drop procedure concat_exec3;
 --enable_query_log
diff --git a/mysql-test/suite/versioning/key_type.combinations b/mysql-test/suite/versioning/key_type.combinations
new file mode 100644
index 00000000000..1929aee9a84
--- /dev/null
+++ b/mysql-test/suite/versioning/key_type.combinations
@@ -0,0 +1,2 @@
+[unique]
+[pk]
diff --git a/mysql-test/suite/versioning/key_type.inc b/mysql-test/suite/versioning/key_type.inc
new file mode 100644
index 00000000000..648430771cf
--- /dev/null
+++ b/mysql-test/suite/versioning/key_type.inc
@@ -0,0 +1,23 @@
+--disable_query_log
+if ($MTR_COMBINATION_UNIQUE)
+{
+    set @KEY_TYPE= 'unique';
+}
+if ($MTR_COMBINATION_PK)
+{
+    set @KEY_TYPE= 'primary key';
+}
+
+delimiter ~~;
+create procedure create_table(name varchar(255), cols varchar(255))
+begin
+  if (cols is null or cols = '') then
+    set cols= '';
+  else
+    set cols= concat(', ', cols);
+  end if;
+  set @str= concat('create or replace table ', name, '(id int ', @KEY_TYPE, cols, ') with system versioning');
+  prepare stmt from @str; execute stmt; drop prepare stmt;
+end~~
+delimiter ;~~
+--enable_query_log
diff --git a/mysql-test/suite/versioning/r/replace.result b/mysql-test/suite/versioning/r/replace.result
new file mode 100644
index 00000000000..e8bbbf36681
--- /dev/null
+++ b/mysql-test/suite/versioning/r/replace.result
@@ -0,0 +1,10 @@
+call create_table('t', 'x int');
+insert t values (1, 2);
+replace t values (1, 3);
+select *, current_row(sys_trx_end) as current from t for system_time all
+order by x;
+id	x	current
+1	2	0
+1	3	1
+drop database test;
+create database test;
diff --git a/mysql-test/suite/versioning/r/update.result b/mysql-test/suite/versioning/r/update.result
index 7505bec0d80..797b309b887 100644
--- a/mysql-test/suite/versioning/r/update.result
+++ b/mysql-test/suite/versioning/r/update.result
@@ -66,14 +66,15 @@ set @str= concat('
   with system versioning
   engine ', engine);
 prepare stmt from @str; execute stmt; drop prepare stmt;
-insert into t1 (x, y) values (1, 1), (2, 1), (3, 1);
+insert into t1 (x, y) values (1, 1), (2, 1), (3, 1), (4, 1), (5, 1);
 start transaction;  
 update t1 set y= y + 1 where x = 3;
+update t1 set y= y + 1 where x = 2;
 update t1 set y= y + 1 where x = 3;
+update t1 set y= y + 1 where x > 3;
+update t1 set y= y + 1 where x > 4;
 commit;
-select x, y from t1 for system_time
-between timestamp '0000-0-0 0:0:0'
-  and timestamp '2038-01-19 04:14:07';
+select x, y, sys_trx_end = 18446744073709551615 as current from t1 for system_time all;
 drop table t1;
 end~~
 create procedure test_04(
@@ -285,19 +286,19 @@ call verify_vtq;
 No	A	B	C	D
 1	1	1	1	1
 2	1	1	1	1
-call test_03('timestamp(6)', 'myisam', 'sys_end');
-x	y
-1	1
-2	1
-3	3
-3	1
-3	2
+# Multiple UPDATE of same rows in single transaction create historical
+# rows only once (applicable to InnoDB only).
 call test_03('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)');
-x	y
-1	1
-2	1
-3	3
-3	1
+x	y	current
+1	1	1
+2	2	1
+3	3	1
+4	2	1
+5	3	1
+3	1	0
+2	1	0
+4	1	0
+5	1	0
 call verify_vtq;
 No	A	B	C	D
 1	1	1	1	1
diff --git a/mysql-test/suite/versioning/t/replace.test b/mysql-test/suite/versioning/t/replace.test
new file mode 100644
index 00000000000..3d8a8191145
--- /dev/null
+++ b/mysql-test/suite/versioning/t/replace.test
@@ -0,0 +1,13 @@
+--source suite/versioning/common.inc
+--source suite/versioning/key_type.inc
+--source suite/versioning/engines.inc
+
+call create_table('t', 'x int');
+
+insert t values (1, 2);
+replace t values (1, 3);
+select *, current_row(sys_trx_end) as current from t for system_time all
+order by x;
+
+drop database test;
+create database test;
diff --git a/mysql-test/suite/versioning/t/update.test b/mysql-test/suite/versioning/t/update.test
index f99d1c6f07b..7f72384b6e5 100644
--- a/mysql-test/suite/versioning/t/update.test
+++ b/mysql-test/suite/versioning/t/update.test
@@ -74,16 +74,17 @@ begin
   engine ', engine);
   prepare stmt from @str; execute stmt; drop prepare stmt;
 
-  insert into t1 (x, y) values (1, 1), (2, 1), (3, 1);
+  insert into t1 (x, y) values (1, 1), (2, 1), (3, 1), (4, 1), (5, 1);
 
   start transaction;  
   update t1 set y= y + 1 where x = 3;
+  update t1 set y= y + 1 where x = 2;
   update t1 set y= y + 1 where x = 3;
+  update t1 set y= y + 1 where x > 3;
+  update t1 set y= y + 1 where x > 4;
   commit;
 
-  select x, y from t1 for system_time
-  between timestamp '0000-0-0 0:0:0'
-  and timestamp '2038-01-19 04:14:07';
+  select x, y, sys_trx_end = 18446744073709551615 as current from t1 for system_time all;
 
   drop table t1;
 end~~
@@ -234,7 +235,8 @@ call test_02('timestamp(6)', 'myisam', 'sys_end');
 call test_02('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)');
 call verify_vtq;
 
-call test_03('timestamp(6)', 'myisam', 'sys_end');
+--echo # Multiple UPDATE of same rows in single transaction create historical
+--echo # rows only once (applicable to InnoDB only).
 call test_03('bigint unsigned', 'innodb', 'vtq_commit_ts(sys_end)');
 call verify_vtq;
 
diff --git a/sql/field.h b/sql/field.h
index fe9c162ef8d..bda7f85e882 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -4642,4 +4642,19 @@ bool check_expression(Virtual_column_info *vcol, LEX_CSTRING *name,
 #define f_bit_as_char(x)        ((x) & FIELDFLAG_TREAT_BIT_AS_CHAR)
 #define f_is_hex_escape(x)      ((x) & FIELDFLAG_HEX_ESCAPE)
 
+inline
+ulonglong TABLE::vers_end_id() const
+{
+  DBUG_ASSERT(versioned_by_engine());
+  return static_cast<ulonglong>(vers_end_field()->val_int());
+}
+
+inline
+ulonglong TABLE::vers_start_id() const
+{
+  DBUG_ASSERT(versioned_by_engine());
+  return static_cast<ulonglong>(vers_start_field()->val_int());
+}
+
+
 #endif /* FIELD_INCLUDED */
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 40ba695499f..44106eb7f54 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1050,7 +1050,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
         }
       }
 
-      if (table->versioned_by_sql())
+      if (table->versioned())
         table->vers_update_fields();
 
       if ((res= table_list->view_check_option(thd,
@@ -1937,15 +1937,30 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
         */
         if (last_uniq_key(table,key_nr) &&
             !table->file->referenced_by_foreign_key() &&
-            (!table->triggers || !table->triggers->has_delete_triggers()) &&
-            !table->versioned_by_sql())
+            (!table->triggers || !table->triggers->has_delete_triggers()))
         {
+          if (table->versioned_by_engine())
+          {
+            bitmap_set_bit(table->write_set, table->vers_start_field()->field_index);
+            table->vers_start_field()->set_notnull();
+            table->vers_start_field()->store(0, false);
+          }
           if ((error=table->file->ha_update_row(table->record[1],
                                                 table->record[0])) &&
               error != HA_ERR_RECORD_IS_THE_SAME)
             goto err;
           if (error != HA_ERR_RECORD_IS_THE_SAME)
+          {
             info->deleted++;
+            if (table->versioned_by_sql())
+            {
+              store_record(table, record[2]);
+              error= vers_insert_history_row(table);
+              restore_record(table, record[2]);
+              if (error)
+                goto err;
+            }
+          }
           else
             error= 0;
           thd->record_first_successful_insert_id_in_cur_stmt(table->file->insert_id_for_cur_row);
@@ -3832,7 +3847,7 @@ int select_insert::send_data(List<Item> &values)
     DBUG_RETURN(0);
 
   thd->count_cuted_fields= CHECK_FIELD_WARN;	// Calculate cuted fields
-  if (table->versioned_by_sql())
+  if (table->versioned())
     table->vers_update_fields();
   store_values(values);
   if (table->default_field && table->update_default_fields(0, info.ignore))
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 6dbce3bd883..4a9a5a18a00 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -781,7 +781,7 @@ int mysql_update(THD *thd,
                                                TRG_EVENT_UPDATE))
         break; /* purecov: inspected */
 
-      if (has_vers_fields && table->versioned_by_sql())
+      if (has_vers_fields && table->versioned())
         table->vers_update_fields();
 
       found++;
@@ -2195,7 +2195,7 @@ int multi_update::send_data(List<Item> &not_used_values)
         if (table->default_field && table->update_default_fields(1, ignore))
           DBUG_RETURN(1);
 
-        if (has_vers_fields && table->versioned_by_sql())
+        if (has_vers_fields && table->versioned())
           table->vers_update_fields();
 
         if ((error= cur_table->view_check_option(thd, ignore)) !=
@@ -2550,7 +2550,7 @@ int multi_update::do_updates()
             goto err2;
           }
         }
-        if (has_vers_fields && table->versioned_by_sql())
+        if (has_vers_fields && table->versioned())
           table->vers_update_fields();
 
         if ((local_error=table->file->ha_update_row(table->record[1],
diff --git a/sql/table.cc b/sql/table.cc
index 65035acce9f..3e479f7edcb 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -7691,11 +7691,14 @@ void TABLE::vers_update_fields()
 {
   DBUG_ENTER("vers_update_fields");
 
-  bitmap_set_bit(write_set, vers_start_field()->field_index);
-  bitmap_set_bit(write_set, vers_end_field()->field_index);
+  if (versioned_by_sql())
+  {
+    bitmap_set_bit(write_set, vers_start_field()->field_index);
+    if (vers_start_field()->set_time())
+      DBUG_ASSERT(0);
+  }
 
-  if (vers_start_field()->set_time())
-    DBUG_ASSERT(0);
+  bitmap_set_bit(write_set, vers_end_field()->field_index);
   vers_end_field()->set_max();
 
   DBUG_VOID_RETURN;
diff --git a/sql/table.h b/sql/table.h
index 4a8dacc79bd..869469f18a0 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1546,6 +1546,9 @@ public:
     return field[s->row_end_field];
   }
 
+  ulonglong vers_start_id() const;
+  ulonglong vers_end_id() const;
+
   int delete_row();
 
 /** Number of additional fields used in versioned tables */
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 9a91fd338c8..b1f706a03ec 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -9185,8 +9185,9 @@ ha_innobase::update_row(
 		error = row_update_for_mysql(m_prebuilt);
 
 		if (error == DB_SUCCESS && vers_ins_row
-		    && trx->id != static_cast<trx_id_t>(
-			    table->vers_start_field()->val_int())) {
+		    /* Multiple UPDATE of same rows in single transaction create
+		       historical rows only once. */
+		    && trx->id != table->vers_start_id()) {
 			error = row_insert_for_mysql((byte*) old_row,
 						     m_prebuilt,
 						     ROW_INS_HISTORICAL);