diff --git a/mysql-test/suite/compat/oracle/r/trigger.result b/mysql-test/suite/compat/oracle/r/trigger.result
new file mode 100644
index 00000000000..c53f9600052
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/r/trigger.result
@@ -0,0 +1,82 @@
+set sql_mode=ORACLE;
+:NEW.a := 1;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'a := 1' at line 1
+:OLD.a := 1;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'a := 1' at line 1
+:OLa.a := 1;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'a := 1' at line 1
+SELECT :NEW.a;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'a' at line 1
+SELECT :OLD.a;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'a' at line 1
+SELECT :OLa.a;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'a' at line 1
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW NEW.a:= 10;
+INSERT INTO t1 VALUES ();
+SELECT * FROM t1;
+a
+10
+DROP TRIGGER tr1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW :NEW.a:= 10;
+INSERT INTO t1 VALUES ();
+SELECT * FROM t1;
+a
+10
+DROP TRIGGER tr1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+IF :NEW.a IS NULL
+THEN
+:NEW.a:= 10;
+END IF;
+END;
+/
+INSERT INTO t1 VALUES (NULL);
+SELECT * FROM t1;
+a
+10
+DROP TRIGGER tr1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER tr1 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+IF :OLD.a IS NULL
+THEN
+:NEW.a:= 10;
+END IF;
+END;
+/
+INSERT INTO t1 VALUES (NULL);
+UPDATE t1 SET a=NULL;
+SELECT * FROM t1;
+a
+10
+DROP TRIGGER tr1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT, b INT, c INT);
+CREATE TRIGGER tr1 BEFORE INSERT ON t1
+FOR EACH ROW
+DECLARE
+cnt INT := 0;
+BEGIN
+IF :NEW.a IS NULL THEN cnt:=cnt+1; END IF;
+IF :NEW.b IS NULL THEN cnt:=cnt+1; END IF;
+IF :NEW.c IS NULL THEN :NEW.c:=cnt; END IF;
+END;
+/
+INSERT INTO t1 VALUES ();
+INSERT INTO t1 VALUES (1, NULL, NULL);
+INSERT INTO t1 VALUES (NULL, 1, NULL);
+INSERT INTO t1 VALUES (1, 1, NULL);
+SELECT * FROM t1;
+a	b	c
+NULL	NULL	2
+1	NULL	1
+NULL	1	1
+1	1	0
+DROP TABLE t1;
diff --git a/mysql-test/suite/compat/oracle/t/trigger.test b/mysql-test/suite/compat/oracle/t/trigger.test
new file mode 100644
index 00000000000..7c9fa5b3858
--- /dev/null
+++ b/mysql-test/suite/compat/oracle/t/trigger.test
@@ -0,0 +1,86 @@
+set sql_mode=ORACLE;
+
+--error ER_PARSE_ERROR
+:NEW.a := 1;
+--error ER_PARSE_ERROR
+:OLD.a := 1;
+--error ER_PARSE_ERROR
+:OLa.a := 1;
+
+--error ER_PARSE_ERROR
+SELECT :NEW.a;
+--error ER_PARSE_ERROR
+SELECT :OLD.a;
+--error ER_PARSE_ERROR
+SELECT :OLa.a;
+
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW NEW.a:= 10;
+INSERT INTO t1 VALUES ();
+SELECT * FROM t1;
+DROP TRIGGER tr1;
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (a INT);
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW :NEW.a:= 10;
+INSERT INTO t1 VALUES ();
+SELECT * FROM t1;
+DROP TRIGGER tr1;
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (a INT);
+DELIMITER /;
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+  IF :NEW.a IS NULL
+  THEN
+    :NEW.a:= 10;
+  END IF;
+END;
+/
+DELIMITER ;/
+INSERT INTO t1 VALUES (NULL);
+SELECT * FROM t1;
+DROP TRIGGER tr1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INT);
+DELIMITER /;
+CREATE TRIGGER tr1 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+  IF :OLD.a IS NULL
+  THEN
+    :NEW.a:= 10;
+  END IF;
+END;
+/
+DELIMITER ;/
+INSERT INTO t1 VALUES (NULL);
+UPDATE t1 SET a=NULL;
+SELECT * FROM t1;
+DROP TRIGGER tr1;
+DROP TABLE t1;
+
+
+
+CREATE TABLE t1 (a INT, b INT, c INT);
+DELIMITER /;
+CREATE TRIGGER tr1 BEFORE INSERT ON t1
+FOR EACH ROW
+DECLARE
+  cnt INT := 0;
+BEGIN
+  IF :NEW.a IS NULL THEN cnt:=cnt+1; END IF;
+  IF :NEW.b IS NULL THEN cnt:=cnt+1; END IF;
+  IF :NEW.c IS NULL THEN :NEW.c:=cnt; END IF;
+END;
+/
+DELIMITER ;/
+INSERT INTO t1 VALUES ();
+INSERT INTO t1 VALUES (1, NULL, NULL);
+INSERT INTO t1 VALUES (NULL, 1, NULL);
+INSERT INTO t1 VALUES (1, 1, NULL);
+SELECT * FROM t1;
+DROP TABLE t1;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index e67536a838d..f7edcb43f9c 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -5132,6 +5132,15 @@ bool LEX::init_internal_variable(struct sys_var_with_base *variable,
 }
 
 
+bool LEX::is_trigger_new_or_old_reference(const LEX_STRING name)
+{
+  return sphead && sphead->m_type == TYPE_ENUM_TRIGGER &&
+         name.length == 3 &&
+         (!my_strcasecmp(system_charset_info, name.str, "NEW") ||
+          !my_strcasecmp(system_charset_info, name.str, "OLD"));
+}
+
+
 bool LEX::init_internal_variable(struct sys_var_with_base *variable,
                                  LEX_STRING dbname, LEX_STRING name)
 {
@@ -5140,9 +5149,7 @@ bool LEX::init_internal_variable(struct sys_var_with_base *variable,
     thd->parse_error();
     return true;
   }
-  if (sphead && sphead->m_type == TYPE_ENUM_TRIGGER &&
-      (!my_strcasecmp(system_charset_info, dbname.str, "NEW") ||
-       !my_strcasecmp(system_charset_info, dbname.str, "OLD")))
+  if (is_trigger_new_or_old_reference(dbname))
   {
     if (dbname.str[0]=='O' || dbname.str[0]=='o')
     {
@@ -5828,6 +5835,46 @@ bool LEX::sp_while_loop_finalize(THD *thd)
 }
 
 
+Item *LEX::create_and_link_Item_trigger_field(THD *thd, const char *name,
+                                                        bool new_row)
+{
+  Item_trigger_field *trg_fld;
+
+  if (trg_chistics.event == TRG_EVENT_INSERT && !new_row)
+  {
+    my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "OLD", "on INSERT");
+    return NULL;
+  }
+
+  if (trg_chistics.event == TRG_EVENT_DELETE && new_row)
+  {
+    my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "NEW", "on DELETE");
+    return NULL;
+  }
+
+  DBUG_ASSERT(!new_row ||
+              (trg_chistics.event == TRG_EVENT_INSERT ||
+               trg_chistics.event == TRG_EVENT_UPDATE));
+
+  const bool tmp_read_only=
+    !(new_row && trg_chistics.action_time == TRG_ACTION_BEFORE);
+  trg_fld= new (thd->mem_root)
+             Item_trigger_field(thd, current_context(),
+                                new_row ?
+                                  Item_trigger_field::NEW_ROW:
+                                  Item_trigger_field::OLD_ROW,
+                                name, SELECT_ACL, tmp_read_only);
+  /*
+    Let us add this item to list of all Item_trigger_field objects
+    in trigger.
+  */
+  if (trg_fld)
+      trg_table_fields.link_in_list(trg_fld, &trg_fld->next_trg_field);
+
+  return trg_fld;
+}
+
+
 #ifdef MYSQL_SERVER
 uint binlog_unsafe_map[256];
 
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index b9cb4e35687..940a54ff009 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -3117,6 +3117,11 @@ public:
                                        const char *start_in_q,
                                        const char *end_in_q);
 
+  bool is_trigger_new_or_old_reference(const LEX_STRING name);
+
+  Item *create_and_link_Item_trigger_field(THD *thd, const char *name,
+                                                     bool new_row);
+
   void sp_block_init(THD *thd, const LEX_STRING label);
   void sp_block_init(THD *thd)
   {
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index f0e36bf3784..febe0d95239 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -13829,45 +13829,13 @@ simple_ident_q:
               we can't meet simple_ident_nospvar in trigger now. But it
               should be changed in future.
             */
-            if (lex->sphead && lex->sphead->m_type == TYPE_ENUM_TRIGGER &&
-                (!my_strcasecmp(system_charset_info, $1.str, "NEW") ||
-                 !my_strcasecmp(system_charset_info, $1.str, "OLD")))
+            if (lex->is_trigger_new_or_old_reference($1))
             {
-              Item_trigger_field *trg_fld;
               bool new_row= ($1.str[0]=='N' || $1.str[0]=='n');
 
-              if (lex->trg_chistics.event == TRG_EVENT_INSERT &&
-                  !new_row)
-                my_yyabort_error((ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "OLD", "on INSERT"));
-
-              if (lex->trg_chistics.event == TRG_EVENT_DELETE &&
-                  new_row)
-                my_yyabort_error((ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "NEW", "on DELETE"));
-
-              DBUG_ASSERT(!new_row ||
-                          (lex->trg_chistics.event == TRG_EVENT_INSERT ||
-                           lex->trg_chistics.event == TRG_EVENT_UPDATE));
-              const bool tmp_read_only=
-                !(new_row && lex->trg_chistics.action_time == TRG_ACTION_BEFORE);
-              trg_fld= new (thd->mem_root)
-                         Item_trigger_field(thd, Lex->current_context(),
-                                            new_row ?
-                                              Item_trigger_field::NEW_ROW:
-                                              Item_trigger_field::OLD_ROW,
-                                            $3.str,
-                                            SELECT_ACL,
-                                            tmp_read_only);
-              if (trg_fld == NULL)
+              if (!($$= lex->create_and_link_Item_trigger_field(thd, $3.str,
+                                                                new_row)))
                 MYSQL_YYABORT;
-
-              /*
-                Let us add this item to list of all Item_trigger_field objects
-                in trigger.
-              */
-              lex->trg_table_fields.link_in_list(trg_fld,
-                                                 &trg_fld->next_trg_field);
-
-              $$= trg_fld;
             }
             else
             {
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index 46344a59b88..360f17b7f7d 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -13482,45 +13482,13 @@ simple_ident_q:
               we can't meet simple_ident_nospvar in trigger now. But it
               should be changed in future.
             */
-            if (lex->sphead && lex->sphead->m_type == TYPE_ENUM_TRIGGER &&
-                (!my_strcasecmp(system_charset_info, $1.str, "NEW") ||
-                 !my_strcasecmp(system_charset_info, $1.str, "OLD")))
+            if (lex->is_trigger_new_or_old_reference($1))
             {
-              Item_trigger_field *trg_fld;
               bool new_row= ($1.str[0]=='N' || $1.str[0]=='n');
 
-              if (lex->trg_chistics.event == TRG_EVENT_INSERT &&
-                  !new_row)
-                my_yyabort_error((ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "OLD", "on INSERT"));
-
-              if (lex->trg_chistics.event == TRG_EVENT_DELETE &&
-                  new_row)
-                my_yyabort_error((ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "NEW", "on DELETE"));
-
-              DBUG_ASSERT(!new_row ||
-                          (lex->trg_chistics.event == TRG_EVENT_INSERT ||
-                           lex->trg_chistics.event == TRG_EVENT_UPDATE));
-              const bool tmp_read_only=
-                !(new_row && lex->trg_chistics.action_time == TRG_ACTION_BEFORE);
-              trg_fld= new (thd->mem_root)
-                         Item_trigger_field(thd, Lex->current_context(),
-                                            new_row ?
-                                              Item_trigger_field::NEW_ROW:
-                                              Item_trigger_field::OLD_ROW,
-                                            $3.str,
-                                            SELECT_ACL,
-                                            tmp_read_only);
-              if (trg_fld == NULL)
+              if (!($$= lex->create_and_link_Item_trigger_field(thd, $3.str,
+                                                                new_row)))
                 MYSQL_YYABORT;
-
-              /*
-                Let us add this item to list of all Item_trigger_field objects
-                in trigger.
-              */
-              lex->trg_table_fields.link_in_list(trg_fld,
-                                                 &trg_fld->next_trg_field);
-
-              $$= trg_fld;
             }
             else
             {
@@ -13545,6 +13513,23 @@ simple_ident_q:
                 MYSQL_YYABORT;
             }
           }
+        | ':' ident '.' ident
+          {
+            LEX *lex= Lex;
+            if (lex->is_trigger_new_or_old_reference($2))
+            {
+              bool new_row= ($2.str[0]=='N' || $2.str[0]=='n');
+              if (!($$= Lex->create_and_link_Item_trigger_field(thd,
+                                                               $4.str,
+                                                               new_row)))
+                MYSQL_YYABORT;
+            }
+            else
+            {
+              thd->parse_error();
+              MYSQL_YYABORT;
+            }
+          }
         | '.' ident '.' ident
           {
             LEX *lex= thd->lex;
@@ -14343,15 +14328,25 @@ set_assign:
           }
           set_expr_or_default
           {
-            sp_pcontext *spc= Lex->spcont;
-            sp_variable *spv= spc->find_variable($1.base_name, false);
+            if ($1.var == trg_new_row_fake_var)
+            {
+              /* We are in trigger and assigning value to field of new row */
+              if (Lex->set_trigger_new_row(&$1.base_name, $4) ||
+                  Lex->sphead->restore_lex(thd))
+                MYSQL_YYABORT;
+            }
+            else
+            {
+              sp_pcontext *spc= Lex->spcont;
+              sp_variable *spv= spc->find_variable($1.base_name, false);
 
-            /* It is a local variable. */
-            if (Lex->set_local_variable(spv, $4))
-              MYSQL_YYABORT;
+              /* It is a local variable. */
+              if (Lex->set_local_variable(spv, $4))
+                MYSQL_YYABORT;
 
-            if (sp_create_assignment_instr(thd, yychar == YYEMPTY))
-              MYSQL_YYABORT;
+              if (sp_create_assignment_instr(thd, yychar == YYEMPTY))
+                MYSQL_YYABORT;
+            }
           }
         ;
 
@@ -14671,6 +14666,16 @@ internal_variable_name_directly_assignable:
             if (Lex->init_default_internal_variable(&$$, $3))
               MYSQL_YYABORT;
           }
+        | ':' ident_directly_assignable '.' ident
+          {
+            if (!Lex->is_trigger_new_or_old_reference($2))
+            {
+              thd->parse_error();
+              MYSQL_YYABORT;
+            }
+            if (Lex->init_internal_variable(&$$, $2, $4))
+              MYSQL_YYABORT;
+          }
         ;
 
 transaction_characteristics: