diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
index 042831bd5..76cd6c527 100644
--- a/lib/ovsdb-idl.c
+++ b/lib/ovsdb-idl.c
@@ -3082,6 +3082,16 @@ ovsdb_idl_txn_commit(struct ovsdb_idl_txn *txn)
     HMAP_FOR_EACH (row, txn_node, &txn->txn_rows) {
         const struct ovsdb_idl_table_class *class = row->table->class_;
 
+        if (!row->table->in_server_schema) {
+            /* The table is not present in the server schema.  Do not
+             * include it in the transaction. */
+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
+            VLOG_WARN_RL(&rl, "%s database lacks %s table, excluding from "
+                         "the txn.", row->table->idl->class_->database,
+                         row->table->class_->name);
+            continue;
+        }
+
         if (!row->new_datum) {
             if (class->is_root) {
                 struct json *op = json_object_create();
@@ -3380,6 +3390,12 @@ ovsdb_idl_txn_write__(const struct ovsdb_idl_row *row_,
     }
 
     class = row->table->class_;
+
+    if (!ovsdb_idl_has_column_in_table(row->table->idl, class->name,
+                                       column->name)) {
+        goto discard_datum;
+    }
+
     column_idx = column - class->columns;
     write_only = row->table->modes[column_idx] == OVSDB_IDL_MONITOR;
 
diff --git a/tests/idltest.ovsschema b/tests/idltest.ovsschema
index 3ddb612b0..65eadb961 100644
--- a/tests/idltest.ovsschema
+++ b/tests/idltest.ovsschema
@@ -210,6 +210,15 @@
       },
       "isRoot": true
     },
+    "simple7" : {
+      "columns" : {
+        "name" : {
+          "type": "string"
+        },
+        "id": {"type": "string"}
+      },
+      "isRoot" : true
+    },
     "singleton" : {
       "columns" : {
         "name" : {
diff --git a/tests/idltest2.ovsschema b/tests/idltest2.ovsschema
index 210e4c389..a8199e56c 100644
--- a/tests/idltest2.ovsschema
+++ b/tests/idltest2.ovsschema
@@ -139,6 +139,13 @@
           "type": "string"
         }
       }
+    },
+    "simple7" : {
+      "columns" : {
+        "name" : {
+          "type": "string"
+        }
+      }
     }
   }
 }
diff --git a/tests/ovsdb-idl.at b/tests/ovsdb-idl.at
index e70994528..4c80251ab 100644
--- a/tests/ovsdb-idl.at
+++ b/tests/ovsdb-idl.at
@@ -999,6 +999,7 @@ test-ovsdb|ovsdb_idl|idltest database lacks simple5 table (database needs upgrad
 test-ovsdb|ovsdb_idl|idltest database lacks simple6 table (database needs upgrade?)
 test-ovsdb|ovsdb_idl|idltest database lacks singleton table (database needs upgrade?)
 test-ovsdb|ovsdb_idl|link1 table in idltest database lacks l2 column (database needs upgrade?)
+test-ovsdb|ovsdb_idl|simple7 table in idltest database lacks id column (database needs upgrade?)
 ])
 
 # Check that ovsdb-idl sent on "monitor" request and that it didn't
@@ -2412,3 +2413,39 @@ column l2 in table link1 is present
 
 OVSDB_SERVER_SHUTDOWN
 AT_CLEANUP
+
+AT_SETUP([idl transaction handling of missing tables and columns - C])
+AT_KEYWORDS([ovsdb client idl txn])
+
+# idltest2.ovsschema is the same as idltest.ovsschema, except that
+# few tables and columns are missing. This test checks that idl doesn't
+# include the missing tables and columns in the transactions.
+# idl-missing-table-column-txn inserts
+#   - a row for table - 'simple'
+#   - a row for table - 'simple5' which is missing.  This should not be
+#                        included in the transaction.
+#   - a row for table - 'simple7 with the missing column 'id'.
+
+AT_CHECK([ovsdb_start_idltest "" "$abs_srcdir/idltest2.ovsschema"])
+AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 idl-missing-table-column-txn unix:socket],
+         [0], [stdout], [stderr])
+AT_CHECK([sort stdout | uuidfilt], [0],
+    [[000: After inserting simple, simple5 and simple7
+001: table simple7: name=simple7 id= uuid=<0>
+001: table simple: i=0 r=0 b=false s=simple u=<1> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2>
+002: End test
+]])
+
+AT_CHECK([grep ovsdb_idl stderr | sort], [0], [dnl
+test-ovsdb|ovsdb_idl|idltest database lacks indexed table (database needs upgrade?)
+test-ovsdb|ovsdb_idl|idltest database lacks link2 table (database needs upgrade?)
+test-ovsdb|ovsdb_idl|idltest database lacks simple5 table (database needs upgrade?)
+test-ovsdb|ovsdb_idl|idltest database lacks simple5 table, excluding from the txn.
+test-ovsdb|ovsdb_idl|idltest database lacks simple6 table (database needs upgrade?)
+test-ovsdb|ovsdb_idl|idltest database lacks singleton table (database needs upgrade?)
+test-ovsdb|ovsdb_idl|link1 table in idltest database lacks l2 column (database needs upgrade?)
+test-ovsdb|ovsdb_idl|simple7 table in idltest database lacks id column (database needs upgrade?)
+])
+
+OVSDB_SERVER_SHUTDOWN
+AT_CLEANUP
diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c
index c476ba80a..35879f8de 100644
--- a/tests/test-ovsdb.c
+++ b/tests/test-ovsdb.c
@@ -2140,6 +2140,17 @@ print_idl_row_simple6(const struct idltest_simple6 *s6, int step)
     print_idl_row_updated_simple6(s6, step);
 }
 
+static void
+print_idl_row_simple7(const struct idltest_simple7 *s7, int step)
+{
+    struct ds msg = DS_EMPTY_INITIALIZER;
+    ds_put_format(&msg, "name=%s id=%s", s7->name, s7->id);
+    char *row_msg = format_idl_row(&s7->header_, step, ds_cstr(&msg));
+    print_and_log("%s", row_msg);
+    ds_destroy(&msg);
+    free(row_msg);
+}
+
 static void
 print_idl_row_singleton(const struct idltest_singleton *sng, int step)
 {
@@ -2164,6 +2175,7 @@ print_idl(struct ovsdb_idl *idl, int step)
     const struct idltest_link1 *l1;
     const struct idltest_link2 *l2;
     const struct idltest_singleton *sng;
+    const struct idltest_simple7 *s7;
     int n = 0;
 
     IDLTEST_SIMPLE_FOR_EACH (s, idl) {
@@ -2194,6 +2206,10 @@ print_idl(struct ovsdb_idl *idl, int step)
         print_idl_row_singleton(sng, step);
         n++;
     }
+    IDLTEST_SIMPLE7_FOR_EACH (s7, idl) {
+        print_idl_row_simple7(s7, step);
+        n++;
+    }
     if (!n) {
         print_and_log("%03d: empty", step);
     }
@@ -3338,6 +3354,41 @@ do_idl_table_column_check(struct ovs_cmdl_context *ctx)
     ovsdb_idl_destroy(idl);
 }
 
+static void
+do_idl_missing_table_column_txn(struct ovs_cmdl_context *ctx)
+{
+    struct ovsdb_idl *idl;
+    struct ovsdb_idl_txn *myTxn;
+    int step = 0;
+
+    idl = ovsdb_idl_create(ctx->argv[1], &idltest_idl_class, true, true);
+
+    ovsdb_idl_get_initial_snapshot(idl);
+
+    ovsdb_idl_run(idl);
+
+    /* Insert a row in simple2. */
+    myTxn = ovsdb_idl_txn_create(idl);
+    struct idltest_simple *simple_row = idltest_simple_insert(myTxn);
+    idltest_simple_set_s(simple_row, "simple");
+
+    /* Insert a row in simple5. simple5 table doesn't exist. */
+    struct idltest_simple5 *simple5_row = idltest_simple5_insert(myTxn);
+    idltest_simple5_set_name(simple5_row, "simple");
+
+    struct idltest_simple7 *simple7_row = idltest_simple7_insert(myTxn);
+    idltest_simple7_set_name(simple7_row, "simple7");
+    idltest_simple7_set_id(simple7_row, "simple7_id");
+
+    ovsdb_idl_txn_commit_block(myTxn);
+    ovsdb_idl_txn_destroy(myTxn);
+    ovsdb_idl_get_initial_snapshot(idl);
+    printf("%03d: After inserting simple, simple5 and simple7\n", step++);
+    print_idl(idl, step++);
+    ovsdb_idl_destroy(idl);
+    printf("%03d: End test\n", step);
+}
+
 static struct ovs_cmdl_command all_commands[] = {
     { "log-io", NULL, 2, INT_MAX, do_log_io, OVS_RO },
     { "default-atoms", NULL, 0, 0, do_default_atoms, OVS_RO },
@@ -3378,6 +3429,8 @@ static struct ovs_cmdl_command all_commands[] = {
         do_idl_partial_update_set_column, OVS_RO },
     { "idl-table-column-check", NULL, 2, INT_MAX,
         do_idl_table_column_check, OVS_RO },
+    { "idl-missing-table-column-txn", NULL, 1, INT_MAX,
+        do_idl_missing_table_column_txn, OVS_RO },
     { "help", NULL, 0, INT_MAX, do_help, OVS_RO },
     { NULL, NULL, 0, 0, NULL, OVS_RO },
 };
