diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig
index 39da85f4..90006e03 100644
--- a/components/lwip/Kconfig
+++ b/components/lwip/Kconfig
@@ -27,6 +27,23 @@ config LWIP_SOCKET_MULTITHREAD
         Enable the option can enable LWIP socket multithread and all
         function will be thread safe.
 
+config ESP_UDP_SYNC_SEND
+    bool "LWIP socket UDP sync send"
+    default y
+    help
+        Enable the option can enable LWIP socket UDP sync send. CPU cost
+        should decrease but memory cost increase and it can make UDP
+        throughput increase a lot.
+
+config ESP_UDP_SYNC_RETRY_MAX
+    int "LWIP socket UDP sync send retry max count"
+    range 1 10
+    default 5
+    depends on ESP_UDP_SYNC_SEND
+    help
+        When UDP sync send count reaches the value, then the packet should
+        be lost and LWIP core thread wake up the up-level send thread.
+
 config LWIP_MAX_SOCKETS
     int "Max number of open sockets"
     range 1 16
diff --git a/components/lwip/lwip/src/api/api_msg.c b/components/lwip/lwip/src/api/api_msg.c
index 95022254..5d086065 100644
--- a/components/lwip/lwip/src/api/api_msg.c
+++ b/components/lwip/lwip/src/api/api_msg.c
@@ -1415,6 +1415,9 @@ lwip_netconn_do_send(void *m)
 #endif
 #if LWIP_UDP
       case NETCONN_UDP:
+#if ESP_UDP
+        udp_sync_regitser(msg);
+#endif /* ESP_UDP */
 #if LWIP_CHECKSUM_ON_COPY
         if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
           msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
@@ -1438,7 +1441,11 @@ lwip_netconn_do_send(void *m)
       }
     }
   }
+#if ESP_UDP
+  udp_sync_ack(msg);
+#else
   TCPIP_APIMSG_ACK(msg);
+#endif /* ESP_UDP */
 }
 
 #if LWIP_TCP
diff --git a/components/lwip/lwip/src/core/timeouts.c b/components/lwip/lwip/src/core/timeouts.c
index 2e0ec540..6d64ac48 100644
--- a/components/lwip/lwip/src/core/timeouts.c
+++ b/components/lwip/lwip/src/core/timeouts.c
@@ -415,6 +415,10 @@ again:
   extern void send_from_list();
   send_from_list();
 
+#if ESP_UDP
+  udp_sync_proc();
+#endif
+
   sleeptime = sys_timeouts_sleeptime();
   if (sleeptime == 0 || sys_arch_mbox_fetch(mbox, msg, sleeptime) == SYS_ARCH_TIMEOUT) {
     /* If a SYS_ARCH_TIMEOUT value is returned, a timeout occurred
diff --git a/components/lwip/port/esp8266/freertos/udp_sync.c b/components/lwip/port/esp8266/freertos/udp_sync.c
new file mode 100644
index 00000000..8ddc8458
--- /dev/null
+++ b/components/lwip/port/esp8266/freertos/udp_sync.c
@@ -0,0 +1,175 @@
+// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stddef.h>
+#include <string.h>
+#include <stdbool.h>
+#include <sys/errno.h>
+#include "lwip/udp.h"
+#include "lwip/priv/api_msg.h"
+#include "lwip/priv/tcp_priv.h"
+
+#include "esp_log.h"
+
+#if ESP_UDP
+
+#define UDP_SYNC_MAX MEMP_NUM_NETCONN
+#define UDP_SYNC_RETRY_MAX CONFIG_ESP_UDP_SYNC_RETRY_MAX
+
+/*
+ * All function has no mutex, so they must put into one task(LWIP main task).
+ */
+
+#if LWIP_TCPIP_CORE_LOCKING
+#define TCPIP_APIMSG_ACK(m)   NETCONN_SET_SAFE_ERR((m)->conn, (m)->err)
+#else /* LWIP_TCPIP_CORE_LOCKING */
+#define TCPIP_APIMSG_ACK(m)   do { NETCONN_SET_SAFE_ERR((m)->conn, (m)->err); sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0)
+#endif /* LWIP_TCPIP_CORE_LOCKING */
+
+typedef struct udp_sync {
+    struct api_msg      *msg;
+
+    int                 ret;
+
+    int                 retry;
+} udp_sync_t;
+
+static const char *TAG = "udp_sync";
+static size_t s_udp_sync_num;
+static udp_sync_t s_udp_sync[UDP_SYNC_MAX];
+static bool s_register_locked;
+static struct api_msg *s_cur_msg;
+
+/*
+ * @brief initialize UDP sync module
+ */
+void udp_sync_init(void)
+{
+    memset(s_udp_sync, 0, sizeof(s_udp_sync));
+    s_register_locked = false;
+    s_udp_sync_num = 0;
+}
+
+/*
+ * @brief register a UDP API message(struct api_msg) to module
+ */
+void udp_sync_regitser(void *in_msg)
+{
+    s_cur_msg = in_msg;
+
+    if (s_register_locked == true)
+        return ;
+
+    struct api_msg *msg = (struct api_msg *)in_msg;
+    int s = msg->conn->socket;
+
+    if (s < 0 || s >= UDP_SYNC_MAX) {
+        ESP_LOGE(TAG, "UDP sync register error, socket is %d", s);
+        return ;
+    } else if (s_udp_sync[s].msg) {
+        ESP_LOGE(TAG, "UDP sync register error, msg is %p", s_udp_sync[s].msg);
+        return ;
+    }
+
+    s_udp_sync_num++;
+    s_udp_sync[s].ret = ERR_OK;
+    s_udp_sync[s].retry = 0;
+    s_udp_sync[s].msg = msg;
+}
+
+/*
+ * @brief ack the message
+ */
+void udp_sync_ack(void *in_msg)
+{
+    struct api_msg *msg = (struct api_msg *)in_msg;
+    int s = msg->conn->socket;
+
+    if (s < 0 || s >= UDP_SYNC_MAX) {
+        ESP_LOGE(TAG, "UDP sync ack error, socket is %d", s);
+        return ;
+    } else if (!s_udp_sync[s].msg) {
+        ESP_LOGE(TAG, "UDP sync ack error, msg is NULL");
+        return ;
+    }
+
+    /* Only cache when low-level has no buffer to send packet */
+    if (s_udp_sync[s].ret != ERR_MEM || s_udp_sync[s].retry >= UDP_SYNC_RETRY_MAX) {
+        s_udp_sync[s].msg = NULL;
+        s_udp_sync[s].retry = 0;
+        s_udp_sync[s].ret = ERR_OK;
+        s_udp_sync_num--;
+
+        /* Todo: return real result */
+        msg->err = ESP_OK;
+
+        TCPIP_APIMSG_ACK(msg);
+    } else {
+        s_udp_sync[s].retry++;
+        ESP_LOGD(TAG, "UDP sync ack error, errno %d", s_udp_sync[s].ret);
+    }
+
+    s_cur_msg = NULL;
+}
+
+/*
+ * @brief set the current message send result
+ */
+void udp_sync_set_ret(int ret)
+{
+    /* Only poll and regitser can set current message */
+    if (!s_cur_msg) {
+        /* You may use it to debug */
+        //ESP_LOGE(TAG, "UDP sync ack error, current message is NULL");
+        return ;
+    }
+
+    struct api_msg *msg = s_cur_msg;
+    int s = msg->conn->socket;
+
+    if (s < 0 || s >= UDP_SYNC_MAX) {
+        ESP_LOGE(TAG, "UDP sync ack error, socket is %d", s);
+        return ;
+    } else if (!s_udp_sync[s].msg) {
+        ESP_LOGE(TAG, "UDP sync ack error, msg is NULL");
+        return ;
+    }
+
+    s_udp_sync[s].ret = ret;
+}
+
+/*
+ * @brief process the sync
+ */
+void udp_sync_proc(void)
+{
+    if (!s_udp_sync_num)
+        return ;
+
+    s_register_locked = true;
+    for (int i = 0; i < UDP_SYNC_MAX; i++) {
+        if (!s_udp_sync[i].msg)
+            continue;
+
+        lwip_netconn_do_send(s_udp_sync[i].msg);
+#if 0
+        //Todo: Add this later
+        if (s_udp_sync[i].ret != ERR_OK)
+            break;
+#endif
+    }
+    s_register_locked = false;
+}
+
+#endif /* ESP_UDP */
diff --git a/components/lwip/port/esp8266/include/lwipopts.h b/components/lwip/port/esp8266/include/lwipopts.h
index a802ec23..97da94dc 100644
--- a/components/lwip/port/esp8266/include/lwipopts.h
+++ b/components/lwip/port/esp8266/include/lwipopts.h
@@ -52,6 +52,10 @@
 
 #define ESP_LWIP 1
 
+#ifdef CONFIG_ESP_UDP_SYNC_SEND
+#define ESP_UDP  1
+#endif
+
 #ifdef CONFIG_LWIP_SOCKET_MULTITHREAD
 #define SOCKETS_MT
 #endif
@@ -2213,4 +2217,12 @@ void *memp_malloc_ll(size_t type);
  * @}
  */
 
+#if ESP_UDP
+#if !LWIP_UDP || !LWIP_SOCKET || !ESP_LWIP
+#error "LWIP_UDP & LWIP_SOCKET & ESP_LWIP must be enable"
+#else
+#include "udp_sync.h"
+#endif
+#endif
+
 #endif /* __LWIP_HDR_LWIPOPTS_H__ */
diff --git a/components/lwip/port/esp8266/include/udp_sync.h b/components/lwip/port/esp8266/include/udp_sync.h
new file mode 100644
index 00000000..29184fbf
--- /dev/null
+++ b/components/lwip/port/esp8266/include/udp_sync.h
@@ -0,0 +1,59 @@
+// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef _UDP_SYNC_H
+#define _UDP_SYNC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * @brief initialize UDP sync module
+ */
+void udp_sync_init(void);
+
+/*
+ * @brief register a UDP API message(struct api_msg) to module
+ * 
+ * @param in_msg message pointer
+ */
+void udp_sync_regitser(void *in_msg);
+
+/*
+ * @brief ack the message
+ * 
+ * @param in_msg message pointer
+ */
+void udp_sync_ack(void *in_msg);
+
+/*
+ * @brief set the current message send result
+ * 
+ * @param ret current message send result
+ */
+void udp_sync_set_ret(int ret);
+
+/*
+ * @brief process the sync
+ * 
+ * @param ret current message send result
+ */
+void udp_sync_proc(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UDP_SYNC_H */
diff --git a/components/lwip/port/esp8266/netif/ethernetif.c b/components/lwip/port/esp8266/netif/ethernetif.c
index e9c5c185..45a7a5d6 100644
--- a/components/lwip/port/esp8266/netif/ethernetif.c
+++ b/components/lwip/port/esp8266/netif/ethernetif.c
@@ -302,6 +302,9 @@ static int8_t low_level_output(struct netif* netif, struct pbuf* p)
      * header, meaning we should not pass target low-level address here.
      */
     err = esp_aio_sendto(&aio, NULL, 0);
+#if ESP_UDP
+    udp_sync_set_ret(err);
+#endif
     if (err != ERR_OK) {
         if (err == ERR_MEM){
             insert_to_list(aio.fd, p);