diff --git a/py/lexer.c b/py/lexer.c
index 6017d69d6dc647823127c6a6d9843e18834fc3c0..e161700b1696b7af0053bada3504a97054dffc7b 100644
--- a/py/lexer.c
+++ b/py/lexer.c
@@ -590,6 +590,8 @@ void mp_lexer_to_next(mp_lexer_t *lex) {
                 }
                 vstr_add_char(&lex->vstr, CUR_CHAR(lex));
                 next_char(lex);
+            } else if (is_char(lex, '_')) {
+                next_char(lex);
             } else {
                 break;
             }
diff --git a/py/parsenum.c b/py/parsenum.c
index 354d0f756c7d66a20f9ab505ef79cf943af088b5..b7e5a3c833d5a4ef4b878d387d89a04fa2f44ac4 100644
--- a/py/parsenum.c
+++ b/py/parsenum.c
@@ -83,6 +83,8 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m
         mp_uint_t dig = *str;
         if ('0' <= dig && dig <= '9') {
             dig -= '0';
+        } else if (dig == '_') {
+            continue;
         } else {
             dig |= 0x20; // make digit lower-case
             if ('a' <= dig && dig <= 'z') {
@@ -273,6 +275,8 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool
             } else if (allow_imag && (dig | 0x20) == 'j') {
                 imag = true;
                 break;
+            } else if (dig == '_') {
+                continue;
             } else {
                 // unknown character
                 str--;
diff --git a/tests/basics/python36.py b/tests/basics/python36.py
new file mode 100644
index 0000000000000000000000000000000000000000..20ecd9227d42b4f46cc5cbbbab789a12f629a121
--- /dev/null
+++ b/tests/basics/python36.py
@@ -0,0 +1,10 @@
+# tests for things that only Python 3.6 supports
+
+# underscores in numeric literals
+print(100_000)
+print(0b1010_0101)
+print(0xff_ff)
+
+# underscore supported by int constructor
+print(int('1_2_3'))
+print(int('0o1_2_3', 8))
diff --git a/tests/basics/python36.py.exp b/tests/basics/python36.py.exp
new file mode 100644
index 0000000000000000000000000000000000000000..4b65daafa18fe8cb05e1a96e747fd8d8848af659
--- /dev/null
+++ b/tests/basics/python36.py.exp
@@ -0,0 +1,5 @@
+100000
+165
+65535
+123
+83
diff --git a/tests/float/python36.py b/tests/float/python36.py
new file mode 100644
index 0000000000000000000000000000000000000000..6e8fb1f21385b3e83a55e66e2af4a5a85ff68a4c
--- /dev/null
+++ b/tests/float/python36.py
@@ -0,0 +1,10 @@
+# tests for things that only Python 3.6 supports, needing floats
+
+# underscores in numeric literals
+print(1_000.1_8)
+print('%.2g' % 1e1_2)
+
+# underscore supported by int/float constructors
+print(float('1_2_3'))
+print(float('1_2_3.4'))
+print('%.2g' % float('1e1_3'))
diff --git a/tests/float/python36.py.exp b/tests/float/python36.py.exp
new file mode 100644
index 0000000000000000000000000000000000000000..3febfed9a0974c7c72d93250fedb86436e9c7887
--- /dev/null
+++ b/tests/float/python36.py.exp
@@ -0,0 +1,5 @@
+1000.18
+1e+12
+123.0
+123.4
+1e+13