diff --git a/mysql-test/r/default.result b/mysql-test/r/default.result
index 8335b553a8e1ebf5a2c2cce9674a69328b0513d2..369734ae92a7bdcc51b99d2534ce07ae0102347a 100644
--- a/mysql-test/r/default.result
+++ b/mysql-test/r/default.result
@@ -3089,8 +3089,8 @@ DROP TABLE t1;
 #
 # Collations
 #
-CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET latin1 DEFAULT CONCAT('ö')) CHARACTER SET koi8r COLLATE koi8r_bin;
-ERROR 22007: Encountered illegal value 'ö' when converting to koi8r
+CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET latin1 DEFAULT CONCAT('�')) CHARACTER SET koi8r COLLATE koi8r_bin;
+ERROR 22007: Encountered illegal value '�' when converting to koi8r
 CREATE OR REPLACE TABLE t1 (a char(2) default concat('A') COLLATE utf8mb4_unicode_ci);
 SHOW CREATE TABLE t1;
 Table	Create Table
diff --git a/mysql-test/suite/gcol/inc/gcol_ins_upd.inc b/mysql-test/suite/gcol/inc/gcol_ins_upd.inc
index 4cfcf371fd779bf2a151c840d7ed942cdd344376..e02a3828ea282fc7c3c13d2dd5a61dad64642f8c 100644
--- a/mysql-test/suite/gcol/inc/gcol_ins_upd.inc
+++ b/mysql-test/suite/gcol/inc/gcol_ins_upd.inc
@@ -660,3 +660,25 @@ INSERT IGNORE INTO t1 SELECT * FROM t1;
 DROP TABLE t1;
 
 }
+
+--echo #
+--echo # MDEV-23597 Assertion `marked_for_read()' failed while evaluating DEFAULT
+--echo #
+
+CREATE TABLE t1 (a INT UNIQUE, b INT DEFAULT (c+1), c int);
+INSERT INTO t1 VALUES (1,1,1);
+UPDATE t1 SET b=DEFAULT;
+SELECT * from t1;
+
+REPLACE t1 VALUES(1,1,1);
+INSERT INTO t1 VALUES (1,1,1) ON DUPLICATE KEY UPDATE b= DEFAULT;
+SELECT * from t1;
+
+REPLACE t1 VALUES(1,1,1);
+CREATE TABLE t2 (a INT, b INT DEFAULT (c+1), c int);
+INSERT INTO t2 VALUES (5,5,5);
+UPDATE t1 join t2 set t1.b= DEFAULT, t2.b= DEFAULT;
+SELECT * from t1, t2;
+
+DROP TABLE t1, t2;
+
diff --git a/mysql-test/suite/gcol/r/gcol_ins_upd_innodb.result b/mysql-test/suite/gcol/r/gcol_ins_upd_innodb.result
index 1d85fc837dc1f325506a74dee156c2d9232d3612..143e1b725c4d5d351495e0743b5c3447ea737cd4 100644
--- a/mysql-test/suite/gcol/r/gcol_ins_upd_innodb.result
+++ b/mysql-test/suite/gcol/r/gcol_ins_upd_innodb.result
@@ -791,6 +791,28 @@ Warnings:
 Warning	1906	The value specified for generated column 'v' in table 't1' has been ignored
 Warning	1906	The value specified for generated column 'v' in table 't1' has been ignored
 DROP TABLE t1;
+#
+# MDEV-23597 Assertion `marked_for_read()' failed while evaluating DEFAULT
+#
+CREATE TABLE t1 (a INT UNIQUE, b INT DEFAULT (c+1), c int);
+INSERT INTO t1 VALUES (1,1,1);
+UPDATE t1 SET b=DEFAULT;
+SELECT * from t1;
+a	b	c
+1	2	1
+REPLACE t1 VALUES(1,1,1);
+INSERT INTO t1 VALUES (1,1,1) ON DUPLICATE KEY UPDATE b= DEFAULT;
+SELECT * from t1;
+a	b	c
+1	2	1
+REPLACE t1 VALUES(1,1,1);
+CREATE TABLE t2 (a INT, b INT DEFAULT (c+1), c int);
+INSERT INTO t2 VALUES (5,5,5);
+UPDATE t1 join t2 set t1.b= DEFAULT, t2.b= DEFAULT;
+SELECT * from t1, t2;
+a	b	c	a	b	c
+1	2	1	5	6	5
+DROP TABLE t1, t2;
 DROP VIEW  IF EXISTS v1,v2;
 DROP TABLE IF EXISTS t1,t2,t3;
 DROP PROCEDURE IF EXISTS p1;
diff --git a/mysql-test/suite/gcol/r/gcol_ins_upd_myisam.result b/mysql-test/suite/gcol/r/gcol_ins_upd_myisam.result
index e10b83cabf52b2e6bd78c80f1d59c055c41f0980..2c883b2de3595240f3f275846e3db8645f22821e 100644
--- a/mysql-test/suite/gcol/r/gcol_ins_upd_myisam.result
+++ b/mysql-test/suite/gcol/r/gcol_ins_upd_myisam.result
@@ -713,6 +713,28 @@ Warnings:
 Warning	1906	The value specified for generated column 'v' in table 't1' has been ignored
 Warning	1906	The value specified for generated column 'v' in table 't1' has been ignored
 DROP TABLE t1;
+#
+# MDEV-23597 Assertion `marked_for_read()' failed while evaluating DEFAULT
+#
+CREATE TABLE t1 (a INT UNIQUE, b INT DEFAULT (c+1), c int);
+INSERT INTO t1 VALUES (1,1,1);
+UPDATE t1 SET b=DEFAULT;
+SELECT * from t1;
+a	b	c
+1	2	1
+REPLACE t1 VALUES(1,1,1);
+INSERT INTO t1 VALUES (1,1,1) ON DUPLICATE KEY UPDATE b= DEFAULT;
+SELECT * from t1;
+a	b	c
+1	2	1
+REPLACE t1 VALUES(1,1,1);
+CREATE TABLE t2 (a INT, b INT DEFAULT (c+1), c int);
+INSERT INTO t2 VALUES (5,5,5);
+UPDATE t1 join t2 set t1.b= DEFAULT, t2.b= DEFAULT;
+SELECT * from t1, t2;
+a	b	c	a	b	c
+1	2	1	5	6	5
+DROP TABLE t1, t2;
 DROP VIEW  IF EXISTS v1,v2;
 DROP TABLE IF EXISTS t1,t2,t3;
 DROP PROCEDURE IF EXISTS p1;
diff --git a/mysql-test/t/default.test b/mysql-test/t/default.test
index 31cf589c48709279a2d5af2715c0c85d1e7e002d..aec518d94a6335c05073e624495955b4dafb0777 100644
--- a/mysql-test/t/default.test
+++ b/mysql-test/t/default.test
@@ -1855,7 +1855,7 @@ DROP TABLE t1;
 --echo #
 
 --error ER_BAD_DATA
-CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET latin1 DEFAULT CONCAT('ö')) CHARACTER SET koi8r COLLATE koi8r_bin;
+CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET latin1 DEFAULT CONCAT('�')) CHARACTER SET koi8r COLLATE koi8r_bin;
 CREATE OR REPLACE TABLE t1 (a char(2) default concat('A') COLLATE utf8mb4_unicode_ci);
 SHOW CREATE TABLE t1;
 DROP TABLE t1;
diff --git a/sql/item.cc b/sql/item.cc
index d7a3659a2cebe421e480e9962dcc8f6d13d8c6a9..96e118e6365087bbbe2540615a9c27c7f39c4a29 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -9003,6 +9003,12 @@ bool Item_default_value::fix_fields(THD *thd, Item **items)
   return TRUE;
 }
 
+bool Item_default_value::enchant_default_with_arg_processor(void *proc_arg)
+{
+  if (!arg) arg= (Item *)proc_arg;
+  return 0;
+}
+
 void Item_default_value::cleanup()
 {
   delete cached_field;                        // Free cached blob data
diff --git a/sql/item.h b/sql/item.h
index cc1914a7ad4023fb6843119342e550b69d392133..8be9a7fe4172b5a0cc1da6528dca1f55ce6dd660 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1713,6 +1713,7 @@ class Item: public Value_source,
   virtual bool limit_index_condition_pushdown_processor(void *arg) { return 0; }
   virtual bool exists2in_processor(void *arg) { return 0; }
   virtual bool find_selective_predicates_list_processor(void *arg) { return 0; }
+  virtual bool enchant_default_with_arg_processor(void *arg) { return 0; }
   bool cleanup_is_expensive_cache_processor(void *arg)
   {
     is_expensive_cache= (int8)(-1);
@@ -5449,6 +5450,11 @@ class Cached_item_field :public Cached_item
 class Item_default_value : public Item_field
 {
   void calculate();
+protected:
+  Item_default_value(THD *thd, Name_resolution_context *context_arg, Item *a)
+          :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
+                      (const char *)NULL),
+           arg(a), cached_field(NULL) {}
 public:
   Item *arg;
   Field *cached_field;
@@ -5456,16 +5462,12 @@ class Item_default_value : public Item_field
     :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
                (const char *)NULL),
     arg(NULL), cached_field(NULL) {}
-  Item_default_value(THD *thd, Name_resolution_context *context_arg, Item *a)
-    :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
-                (const char *)NULL),
-    arg(a), cached_field(NULL) {}
   Item_default_value(THD *thd, Name_resolution_context *context_arg, Field *a)
     :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
                 (const char *)NULL),
     arg(NULL),cached_field(NULL) {}
   enum Type type() const { return DEFAULT_VALUE_ITEM; }
-  bool vcol_assignment_allowed_value() const { return arg == NULL; }
+  bool vcol_assignment_allowed_value() const { return true; }
   bool eq(const Item *item, bool binary_cmp) const;
   bool fix_fields(THD *, Item **);
   void cleanup();
@@ -5495,6 +5497,7 @@ class Item_default_value : public Item_field
   Item_field *field_for_view_update() { return 0; }
   bool update_vcol_processor(void *arg) { return 0; }
   bool check_func_default_processor(void *arg) { return true; }
+  bool enchant_default_with_arg_processor(void *arg);
 
   bool walk(Item_processor processor, bool walk_subquery, void *args)
   {
@@ -5505,6 +5508,15 @@ class Item_default_value : public Item_field
   Item *transform(THD *thd, Item_transformer transformer, uchar *args);
 };
 
+class Item_default_value_arg: public Item_default_value
+{
+public:
+  Item_default_value_arg(THD *thd, Name_resolution_context *context, Item *a)
+    :Item_default_value(thd, context, a) {}
+
+  bool vcol_assignment_allowed_value() const { return arg == NULL; }
+};
+
 /**
   This class is used as bulk parameter INGNORE representation.
 
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 3471297ac7d72e439524863dc16401c050d71831..9a66b27a45464ed50fc0dfc9bdcf26d7d51abc83 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -7193,6 +7193,18 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
   DBUG_RETURN(0);
 }
 
+/** Transforms b= F(DEFAULT) -> b= F(DEFAULT(b)) */
+void setup_defaults(THD *thd, List<Item> &fields, List<Item> &values)
+{
+  List_iterator<Item> fit(fields);
+  List_iterator<Item> vit(values);
+
+  for (Item *value= vit++, *f_item= fit++; value; value= vit++, f_item= fit++)
+  {
+    value->walk(&Item::enchant_default_with_arg_processor, false, f_item);
+  }
+}
+
 /****************************************************************************
 ** Check that all given fields exists and fill struct with current data
 ****************************************************************************/
diff --git a/sql/sql_base.h b/sql/sql_base.h
index 5674e8378c5aac01ee9f4cb92da15080967a4fa0..b3b0a11795dab7c04c045bac899889dbe912ce88 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -172,6 +172,7 @@ bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array,
                   List<Item> &item, enum_mark_columns mark_used_columns,
                   List<Item> *sum_func_list, List<Item> *pre_fix,
                   bool allow_sum_func);
+void setup_defaults(THD *thd, List<Item> &fields, List<Item> &values);
 void unfix_fields(List<Item> &items);
 bool fill_record(THD * thd, TABLE *table_arg, List<Item> &fields,
                  List<Item> &values, bool ignore_errors, bool update);
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 8af6c8f80a2e50b98f8947507af1ecaa113f5e37..0344d8e0082df0802f2b9523ebf01d6a1366f79f 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -370,6 +370,8 @@ int mysql_update(THD *thd,
     DBUG_RETURN(1);
   }
 
+  setup_defaults(thd, fields, values);
+
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
   /* Check values */
   table_list->grant.want_privilege= table->grant.want_privilege=
@@ -1749,6 +1751,8 @@ int multi_update::prepare(List<Item> &not_used_values,
     }
   }
 
+  setup_defaults(thd, *fields, *values);
+
   /*
     We have to check values after setup_tables to get covering_keys right in
     reference tables
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 25826d2d6b017177a97c3aea4c4ddac78fe92f24..ec82c7f9f07f494cd0385851fd6fdfb38c737f73 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -9466,8 +9466,8 @@ column_default_non_parenthesized_expr:
             Item_splocal *il= $3->get_item_splocal();
             if (il)
               my_yyabort_error((ER_WRONG_COLUMN_NAME, MYF(0), il->my_name()->str));
-            $$= new (thd->mem_root) Item_default_value(thd, Lex->current_context(),
-                                                         $3);
+            $$= new (thd->mem_root) Item_default_value_arg(thd, Lex->current_context(),
+                                                           $3);
             if ($$ == NULL)
               MYSQL_YYABORT;
           }