diff --git a/component/mmdb/mmdb.go b/component/mmdb/mmdb.go
new file mode 100644
index 00000000..58f3fe00
--- /dev/null
+++ b/component/mmdb/mmdb.go
@@ -0,0 +1,44 @@
+package mmdb
+
+import (
+	"github.com/oschwald/geoip2-golang"
+	"sync"
+
+	C "github.com/Dreamacro/clash/constant"
+	"github.com/Dreamacro/clash/log"
+)
+
+var (
+	mmdb *geoip2.Reader
+	once sync.Once
+)
+
+func LoadFromBytes(buffer []byte) {
+	once.Do(func() {
+		var err error
+		mmdb, err = geoip2.FromBytes(buffer)
+		if err != nil {
+			log.Fatalln("Can't load mmdb: %s", err.Error())
+		}
+	})
+}
+
+func Verify() bool {
+	instance, err := geoip2.Open(C.Path.MMDB())
+	if err == nil {
+		instance.Close()
+	}
+	return err == nil
+}
+
+func Instance() *geoip2.Reader {
+	once.Do(func() {
+		var err error
+		mmdb, err = geoip2.Open(C.Path.MMDB())
+		if err != nil {
+			log.Fatalln("Can't load mmdb: %s", err.Error())
+		}
+	})
+
+	return mmdb
+}
diff --git a/config/initial.go b/config/initial.go
index 5363d3ba..b2acaa2a 100644
--- a/config/initial.go
+++ b/config/initial.go
@@ -2,6 +2,7 @@ package config
 
 import (
 	"fmt"
+	"github.com/Dreamacro/clash/component/mmdb"
 	"io"
 	"net/http"
 	"os"
@@ -10,6 +11,23 @@ import (
 	"github.com/Dreamacro/clash/log"
 )
 
+func downloadMMDB(path string) (err error) {
+	resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/geoip@release/Country.mmdb")
+	if err != nil {
+		return
+	}
+	defer resp.Body.Close()
+
+	f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0o644)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	_, err = io.Copy(f, resp.Body)
+
+	return err
+}
+
 func downloadGeoIP(path string) (err error) {
 	resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat")
 	if err != nil {
@@ -65,6 +83,24 @@ func initGeoIP() error {
 		log.Infoln("Download GeoIP.dat finish")
 	}
 
+	if _, err := os.Stat(C.Path.MMDB()); os.IsNotExist(err) {
+		log.Infoln("Can't find MMDB, start download")
+		if err := downloadMMDB(C.Path.MMDB()); err != nil {
+			return fmt.Errorf("can't download MMDB: %s", err.Error())
+		}
+	}
+
+	if !mmdb.Verify() {
+		log.Warnln("MMDB invalid, remove and download")
+		if err := os.Remove(C.Path.MMDB()); err != nil {
+			return fmt.Errorf("can't remove invalid MMDB: %s", err.Error())
+		}
+
+		if err := downloadMMDB(C.Path.MMDB()); err != nil {
+			return fmt.Errorf("can't download MMDB: %s", err.Error())
+		}
+	}
+
 	return nil
 }
 
diff --git a/constant/path.go b/constant/path.go
index 4ace7ab0..31b1ef80 100644
--- a/constant/path.go
+++ b/constant/path.go
@@ -60,6 +60,21 @@ func (p *path) Resolve(path string) string {
 }
 
 func (p *path) MMDB() string {
+	files, err := ioutil.ReadDir(p.homeDir)
+	if err != nil {
+		return ""
+	}
+	for _, fi := range files {
+		if fi.IsDir() {
+			// 目录则直接跳过
+			continue
+		} else {
+			if strings.EqualFold(fi.Name(), "Country.mmdb") {
+				GeoipName = fi.Name()
+				return P.Join(p.homeDir, fi.Name())
+			}
+		}
+	}
 	return P.Join(p.homeDir, "Country.mmdb")
 }
 
diff --git a/go.mod b/go.mod
index 0adc2ad5..4b6bbaf9 100644
--- a/go.mod
+++ b/go.mod
@@ -14,6 +14,7 @@ require (
 	github.com/kr328/tun2socket v0.0.0-20210412191540-3d56c47e2d99
 	github.com/lucas-clemente/quic-go v0.25.0
 	github.com/miekg/dns v1.1.45
+	github.com/oschwald/geoip2-golang v1.6.1
 	github.com/sirupsen/logrus v1.8.1
 	github.com/stretchr/testify v1.7.0
 	github.com/xtls/go v0.0.0-20210920065950-d4af136d3672
@@ -42,6 +43,7 @@ require (
 	github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1 // indirect
 	github.com/nxadm/tail v1.4.8 // indirect
 	github.com/onsi/ginkgo v1.16.4 // indirect
+	github.com/oschwald/maxminddb-golang v1.8.0 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
 	golang.org/x/mod v0.4.2 // indirect
diff --git a/go.sum b/go.sum
index 3028c065..499fb380 100644
--- a/go.sum
+++ b/go.sum
@@ -367,6 +367,10 @@ github.com/opencontainers/runc v1.0.0-rc90/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2r
 github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
 github.com/opencontainers/runtime-spec v1.0.3-0.20211123151946-c2389c3cb60a/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
 github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
+github.com/oschwald/geoip2-golang v1.6.1 h1:GKxT3yaWWNXSb7vj6D7eoJBns+lGYgx08QO0UcNm0YY=
+github.com/oschwald/geoip2-golang v1.6.1/go.mod h1:xdvYt5xQzB8ORWFqPnqMwZpCpgNagttWdoZLlJQzg7s=
+github.com/oschwald/maxminddb-golang v1.8.0 h1:Uh/DSnGoxsyp/KYbY1AuP0tYEwfs0sCph9p/UMXK/Hk=
+github.com/oschwald/maxminddb-golang v1.8.0/go.mod h1:RXZtst0N6+FY/3qCNmZMBApR19cdQj43/NM9VkrNAis=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -654,6 +658,7 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=