guide.rst 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. .. _guide:
  2. ==========
  3. User Guide
  4. ==========
  5. --------------
  6. Authentication
  7. --------------
  8. The emqttd broker supports to authenticate MQTT client with ClientID, Username/Password, IpAddress and even HTTP Cookies.
  9. The authentication is provided by a list of extended modules, or MySQL, PostgreSQL and Redis Plugins.
  10. Enable an authentication module in etc/emqttd.config::
  11. %% Authentication and Authorization
  12. {access, [
  13. %% Authetication. Anonymous Default
  14. {auth, [
  15. %% Authentication with username, password
  16. %{username, []},
  17. %% Authentication with clientid
  18. %{clientid, [{password, no}, {file, "etc/clients.config"}]},
  19. %% Authentication with LDAP
  20. % {ldap, [
  21. % {servers, ["localhost"]},
  22. % {port, 389},
  23. % {timeout, 30},
  24. % {user_dn, "uid=$u,ou=People,dc=example,dc=com"},
  25. % {ssl, fasle},
  26. % {sslopts, [
  27. % {"certfile", "ssl.crt"},
  28. % {"keyfile", "ssl.key"}]}
  29. % ]},
  30. %% Allow all
  31. {anonymous, []}
  32. ]},
  33. .. NOTE:: "%%" comments the line.
  34. If we enable several modules in the same time, the authentication process::
  35. ---------------- ---------------- -------------
  36. Client --> | Username | -ignore-> | ClientID | -ignore-> | Anonymous |
  37. ---------------- ---------------- -------------
  38. | | |
  39. \|/ \|/ \|/
  40. allow | deny allow | deny allow | deny
  41. The authentication plugins developed by emqttd:
  42. +---------------------------+---------------------------+
  43. | Plugin | Description |
  44. +===========================+===========================+
  45. | `emqttd_plugin_mysql`_ | MySQL Auth/ACL Plugin |
  46. +---------------------------+---------------------------+
  47. | `emqttd_plugin_pgsql`_ | PostgreSQL Auth/ACL Plugin|
  48. +---------------------------+---------------------------+
  49. | `emqttd_plugin_redis`_ | Redis Auth/ACL Plugin |
  50. +---------------------------+---------------------------+
  51. .. NOTE:: If we load an authentication plugin, the authentication modules will be disabled.
  52. Username
  53. --------
  54. Authenticate MQTT client with Username/Password::
  55. {username, [{client1, "passwd1"}, {client1, "passwd2"}]},
  56. Two ways to add users:
  57. 1. Configure username and plain password directly::
  58. {username, [{client1, "passwd1"}, {client1, "passwd2"}]},
  59. 2. Add user by './bin/emqttd_ctl users' command::
  60. $ ./bin/emqttd_ctl users add <Username> <Password>
  61. ClientId
  62. --------
  63. .. code:: erlang
  64. {clientid, [{password, no}, {file, "etc/clients.config"}]},
  65. Configure ClientIDs in etc/clients.config::
  66. testclientid0
  67. testclientid1 127.0.0.1
  68. testclientid2 192.168.0.1/24
  69. LDAP
  70. ----
  71. .. code:: erlang
  72. {ldap, [
  73. {servers, ["localhost"]},
  74. {port, 389},
  75. {timeout, 30},
  76. {user_dn, "uid=$u,ou=People,dc=example,dc=com"},
  77. {ssl, fasle},
  78. {sslopts, [
  79. {"certfile", "ssl.crt"},
  80. {"keyfile", "ssl.key"}]}
  81. ]},
  82. Anonymous
  83. ---------
  84. Allow any client to connect to the broker::
  85. {anonymous, []}
  86. MySQL Plugin
  87. ------------
  88. Authenticate against MySQL database. Support we create a mqtt_user table::
  89. CREATE TABLE `mqtt_user` (
  90. `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  91. `username` varchar(100) DEFAULT NULL,
  92. `password` varchar(100) DEFAULT NULL,
  93. `salt` varchar(20) DEFAULT NULL,
  94. `created` datetime DEFAULT NULL,
  95. PRIMARY KEY (`id`),
  96. UNIQUE KEY `mqtt_username` (`username`)
  97. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  98. Configure the 'authquery' and 'password_hash' in emqttd_plugin_mysql/etc/plugin.config::
  99. [
  100. {emqttd_plugin_mysql, [
  101. ...
  102. %% select password only
  103. {authquery, "select password from mqtt_user where username = '%u' limit 1"},
  104. %% hash algorithm: md5, sha, sha256, pbkdf2?
  105. {password_hash, sha256},
  106. ...
  107. ]}
  108. ].
  109. Load the plugin::
  110. ./bin/emqttd_ctl plugins load emqttd_plugin_mysql
  111. PostgreSQL Plugin
  112. -----------------
  113. Authenticate against PostgreSQL database. Create a mqtt_user table::
  114. CREATE TABLE mqtt_user (
  115. id SERIAL primary key,
  116. username character varying(100),
  117. password character varying(100),
  118. salt character varying(40)
  119. );
  120. Configure the 'authquery' and 'password_hash' in emqttd_plugin_pgsql/etc/plugin.config::
  121. [
  122. {emqttd_plugin_pgsql, [
  123. ...
  124. %% select password only
  125. {authquery, "select password from mqtt_user where username = '%u' limit 1"},
  126. %% hash algorithm: md5, sha, sha256, pbkdf2?
  127. {password_hash, sha256},
  128. ...
  129. ]}
  130. ].
  131. Load the plugin::
  132. ./bin/emqttd_ctl plugins load emqttd_plugin_pgsql
  133. Redis
  134. -----
  135. Authenticate against Redis. Support we store mqtt user in an redis HASH, the key is "mqtt_user:<Username>".
  136. Configure 'authcmd' and 'password_hash' in emqttd_plugin_redis/etc/plugin.config::
  137. [
  138. {emqttd_plugin_redis, [
  139. ...
  140. %% HMGET mqtt_user:%u password
  141. {authcmd, ["HGET", "mqtt_user:%u", "password"]},
  142. %% Password hash algorithm: plain, md5, sha, sha256, pbkdf2?
  143. {password_hash, sha256},
  144. ...
  145. ]}
  146. ].
  147. Load the plugin::
  148. ./bin/emqttd_ctl plugins load emqttd_plugin_redis
  149. ---
  150. ACL
  151. ---
  152. The ACL of emqttd broker is responsbile for authorizing MQTT clients to publish/subscribe topics.
  153. The ACL consists of a list rules that define::
  154. Allow|Deny Who Publish|Subscribe Topics
  155. Access Control Module of emqttd broker will match the rules one by one::
  156. --------- --------- ---------
  157. Client -> | Rule1 | --nomatch--> | Rule2 | --nomatch--> | Rule3 | --> Default
  158. --------- --------- ---------
  159. | | |
  160. match match match
  161. \|/ \|/ \|/
  162. allow | deny allow | deny allow | deny
  163. Internal
  164. --------
  165. ACL of emqttd broker is implemented by an 'internal' module by default.
  166. Enable the 'internal' ACL module in etc/emqttd.config::
  167. {acl, [
  168. %% Internal ACL module
  169. {internal, [{file, "etc/acl.config"}, {nomatch, allow}]}
  170. ]}
  171. The ACL rules of 'internal' module are defined in 'etc/acl.config' file::
  172. %% Allow 'dashboard' to subscribe '$SYS/#'
  173. {allow, {user, "dashboard"}, subscribe, ["$SYS/#"]}.
  174. %% Allow clients from localhost to subscribe any topics
  175. {allow, {ipaddr, "127.0.0.1"}, pubsub, ["$SYS/#", "#"]}.
  176. %% Deny clients to subscribe '$SYS#' and '#'
  177. {deny, all, subscribe, ["$SYS/#", {eq, "#"}]}.
  178. %% Allow all by default
  179. {allow, all}.
  180. MySQL
  181. -----
  182. ACL against MySQL database. The mqtt_acl table and default data::
  183. CREATE TABLE `mqtt_acl` (
  184. `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  185. `allow` int(1) DEFAULT NULL COMMENT '0: deny, 1: allow',
  186. `ipaddr` varchar(60) DEFAULT NULL COMMENT 'IpAddress',
  187. `username` varchar(100) DEFAULT NULL COMMENT 'Username',
  188. `clientid` varchar(100) DEFAULT NULL COMMENT 'ClientId',
  189. `access` int(2) NOT NULL COMMENT '1: subscribe, 2: publish, 3: pubsub',
  190. `topic` varchar(100) NOT NULL DEFAULT '' COMMENT 'Topic Filter',
  191. PRIMARY KEY (`id`)
  192. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  193. INSERT INTO mqtt_acl (id, allow, ipaddr, username, clientid, access, topic)
  194. VALUES
  195. (1,1,NULL,'$all',NULL,2,'#'),
  196. (2,0,NULL,'$all',NULL,1,'$SYS/#'),
  197. (3,0,NULL,'$all',NULL,1,'eq #'),
  198. (5,1,'127.0.0.1',NULL,NULL,2,'$SYS/#'),
  199. (6,1,'127.0.0.1',NULL,NULL,2,'#'),
  200. (7,1,NULL,'dashboard',NULL,1,'$SYS/#');
  201. Configure 'aclquery' and 'acl_nomatch' in emqttd_plugin_mysql/etc/plugin.config::
  202. [
  203. {emqttd_plugin_mysql, [
  204. ...
  205. %% comment this query, the acl will be disabled
  206. {aclquery, "select * from mqtt_acl where ipaddr = '%a' or username = '%u' or username = '$all' or clientid = '%c'"},
  207. %% If no rules matched, return...
  208. {acl_nomatch, allow}
  209. ]}
  210. ].
  211. PostgreSQL
  212. ----------
  213. ACL against PostgreSQL database. The mqtt_acl table and default data::
  214. CREATE TABLE mqtt_acl (
  215. id SERIAL primary key,
  216. allow integer,
  217. ipaddr character varying(60),
  218. username character varying(100),
  219. clientid character varying(100),
  220. access integer,
  221. topic character varying(100)
  222. );
  223. INSERT INTO mqtt_acl (id, allow, ipaddr, username, clientid, access, topic)
  224. VALUES
  225. (1,1,NULL,'$all',NULL,2,'#'),
  226. (2,0,NULL,'$all',NULL,1,'$SYS/#'),
  227. (3,0,NULL,'$all',NULL,1,'eq #'),
  228. (5,1,'127.0.0.1',NULL,NULL,2,'$SYS/#'),
  229. (6,1,'127.0.0.1',NULL,NULL,2,'#'),
  230. (7,1,NULL,'dashboard',NULL,1,'$SYS/#');
  231. Configure 'aclquery' and 'acl_nomatch' in emqttd_plugin_pgsql/etc/plugin.config::
  232. [
  233. {emqttd_plugin_pgsql, [
  234. ...
  235. %% Comment this query, the acl will be disabled. Notice: don't edit this query!
  236. {aclquery, "select allow, ipaddr, username, clientid, access, topic from mqtt_acl
  237. where ipaddr = '%a' or username = '%u' or username = '$all' or clientid = '%c'"},
  238. %% If no rules matched, return...
  239. {acl_nomatch, allow}
  240. ...
  241. ]}
  242. ].
  243. Redis
  244. -----
  245. ACL against Redis. We store ACL rules for each MQTT client in Redis List by defualt. The key is "mqtt_acl:<Username>", the value is a list of "publish <Topic>", "subscribe <Topic>" or "pubsub <Topic>".
  246. Configure 'aclcmd' and 'acl_nomatch' in emqttd_plugin_redis/etc/plugin.config::
  247. [
  248. {emqttd_plugin_redis, [
  249. ...
  250. %% SMEMBERS mqtt_acl:%u
  251. {aclcmd, ["SMEMBERS", "mqtt_acl:%u"]},
  252. %% If no rules matched, return...
  253. {acl_nomatch, deny},
  254. ...
  255. ]}
  256. ].
  257. ----------------------
  258. MQTT Publish/Subscribe
  259. ----------------------
  260. MQTT is a an extremely lightweight publish/subscribe messaging protocol desgined for IoT, M2M and Mobile applications.
  261. .. image:: _static/images/pubsub_concept.png
  262. Install and start the emqttd broker, and then any MQTT client could connect to the broker, subscribe topics and publish messages.
  263. MQTT Client Libraries: https://github.com/mqtt/mqtt.github.io/wiki/libraries
  264. For example, we use mosquitto_sub/pub commands::
  265. mosquitto_sub -t topic -q 2
  266. mosquitto_pub -t topic -q 1 -m "Hello, MQTT!"
  267. MQTT V3.1.1 Protocol Specification: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/mqtt-v3.1.1.html
  268. MQTT Listener of emqttd broker is configured in etc/emqttd.config::
  269. {mqtt, 1883, [
  270. %% Size of acceptor pool
  271. {acceptors, 16},
  272. %% Maximum number of concurrent clients
  273. {max_clients, 512},
  274. %% Socket Access Control
  275. {access, [{allow, all}]},
  276. %% Connection Options
  277. {connopts, [
  278. %% Rate Limit. Format is 'burst, rate', Unit is KB/Sec
  279. %% {rate_limit, "100,10"} %% 100K burst, 10K rate
  280. ]},
  281. %% Socket Options
  282. {sockopts, [
  283. %Set buffer if hight thoughtput
  284. %{recbuf, 4096},
  285. %{sndbuf, 4096},
  286. %{buffer, 4096},
  287. %{nodelay, true},
  288. {backlog, 512}
  289. ]}
  290. ]},
  291. MQTT(SSL) Listener, Default Port is 8883::
  292. {mqtts, 8883, [
  293. %% Size of acceptor pool
  294. {acceptors, 4},
  295. %% Maximum number of concurrent clients
  296. {max_clients, 512},
  297. %% Socket Access Control
  298. {access, [{allow, all}]},
  299. %% SSL certificate and key files
  300. {ssl, [{certfile, "etc/ssl/ssl.crt"},
  301. {keyfile, "etc/ssl/ssl.key"}]},
  302. %% Socket Options
  303. {sockopts, [
  304. {backlog, 1024}
  305. %{buffer, 4096},
  306. ]}
  307. ]},
  308. ----------------
  309. HTTP Publish API
  310. ----------------
  311. The emqttd broker provides a HTTP API to help application servers to publish messages to MQTT clients.
  312. HTTP API: POST http://host:8083/mqtt/publish
  313. Web servers such as PHP, Java, Python, NodeJS and Ruby on Rails could use HTTP POST to publish MQTT messages to the broker::
  314. curl -v --basic -u user:passwd -d "qos=1&retain=0&topic=/a/b/c&message=hello from http..." -k http://localhost:8083/mqtt/publish
  315. Parameters of the HTTP API:
  316. +---------+----------------+
  317. | Name | Description |
  318. +=========+================+
  319. | client | clientid |
  320. +---------+----------------+
  321. | qos | QoS(0, 1, 2) |
  322. +---------+----------------+
  323. | retain | Retain(0, 1) |
  324. +---------+----------------+
  325. | topic | Topic |
  326. +---------+----------------+
  327. | message | Payload |
  328. +---------+----------------+
  329. .. NOTE:: The API use HTTP Basic Authentication.
  330. -------------------
  331. MQTT Over WebSocket
  332. -------------------
  333. Web browsers could connect to the emqttd broker directly by MQTT Over WebSocket.
  334. +-------------------------+----------------------------+
  335. | WebSocket URI: | ws(s)://host:8083/mqtt |
  336. +-------------------------+----------------------------+
  337. | Sec-WebSocket-Protocol: | 'mqttv3.1' or 'mqttv3.1.1' |
  338. +-------------------------+----------------------------+
  339. The Dashboard plugin provides a test page for WebSocket::
  340. http://127.0.0.1:18083/websocket.html
  341. Listener of WebSocket and HTTP Publish API is configured in etc/emqttd.config::
  342. %% HTTP and WebSocket Listener
  343. {http, 8083, [
  344. %% Size of acceptor pool
  345. {acceptors, 4},
  346. %% Maximum number of concurrent clients
  347. {max_clients, 64},
  348. %% Socket Access Control
  349. {access, [{allow, all}]},
  350. %% Socket Options
  351. {sockopts, [
  352. {backlog, 1024}
  353. %{buffer, 4096},
  354. ]}
  355. ]}
  356. ## Overview
  357. emqttd could trace packets received/sent from/to specific client, or trace publish/subscribe to specific topic.
  358. emqttd use lager:trace_file api and write trace log to file.
  359. ## Trace Commands
  360. ### Trace client
  361. ```
  362. ./bin/emqttd_ctl trace client "ClientId" "trace_clientid.log"
  363. ```
  364. ### Trace topic
  365. ```
  366. ./bin/emqttd_ctl trace topic "Topic" "trace_topic.log"
  367. ```
  368. ### Stop Trace
  369. ```
  370. ./bin/emqttd_ctl trace client "ClientId" off
  371. ./bin/emqttd_ctl trace topic "Topic" off
  372. ```
  373. ### Lookup Traces
  374. ```
  375. ./bin/emqttd_ctl trace list
  376. ```
  377. -----------
  378. $SYS Topics
  379. -----------
  380. NOTICE: This is the design of 0.9.0 release
  381. ## Overview
  382. For emqttd is clustered, $SYS Topics of broker is started with:
  383. ```
  384. $SYS/brokers/${node}
  385. ```
  386. ${node} is erlang node of clustered brokers. For example:
  387. ```
  388. $SYS/brokers/emqttd@host1/version
  389. $SYS/brokers/emqttd@host2/version
  390. ```
  391. ## Broker $SYS Topics
  392. Topic | Description
  393. -------------------------------|------------
  394. $SYS/brokers | Broker nodes
  395. $SYS/brokers/${node}/version | Broker Version
  396. $SYS/brokers/${node}/uptime | Broker Uptime
  397. $SYS/brokers/${node}/datetime | Broker DateTime
  398. $SYS/brokers/${node}/sysdescr | Broker Description
  399.  
  400. ## Client $SYS Topics
  401. Start with: $SYS/brokers/${node}/clients/
  402. Topic | Payload(json) | Description
  403. ----------------------|---------------------|---------------
  404. ${clientid}/connected | {ipaddress: "127.0.0.1", username: "test", session: false, version: 3, connack: 0, ts: 1432648482} | Publish when client connected
  405. ${clientid}/disconnected | {reason: "normal" | "keepalive_timeout" | "conn_closed"}
  406. Parameters of 'connected' Payload:
  407. ```
  408. ipaddress: "127.0.0.1",
  409. username: "test",
  410. session: false,
  411. protocol: 3,
  412. connack: 0,
  413. ts: 1432648482
  414. ```
  415. Parameters of 'disconnected' Payload:
  416. ```
  417. reason: normal,
  418. ts: 1432648486
  419. ```
  420. ## Statistics $SYS Topics
  421. Start with '$SYS/brokers/${node}/stats/'
  422. ### Client Stats
  423. Topic | Description
  424. -------------------------------------|------------
  425. clients/count | count of current connected clients
  426. clients/max | max connected clients in the same time
  427. ### Session Stats
  428. Topic | Description
  429. -----------------|------------
  430. sessions/count | count of current sessions
  431. sessions/max | max number of sessions
  432. ### Subscriber Stats
  433. Topic | Description
  434. ------------------|------------
  435. subscriptions/count | count of current subscriptions
  436. subscriptions/max | max number of subscriptions
  437. ### Topic Stats
  438. Topic | Description
  439. ------------------|------------
  440. topics/count | count of current topics
  441. topics/max | max number of topics
  442. ### Queue Stats
  443. Topic | Description
  444. ------------------|------------
  445. queues/count | count of current queues
  446. queues/max | max number of queues
  447. ## Metrics $SYS Topics
  448. Start with '$SYS/brokers/${node}/metrics/'
  449. ### Bytes sent and received
  450. Topic | Description
  451. ------------------------------------|------------
  452. bytes/received | MQTT Bytes Received since broker started
  453. bytes/sent | MQTT Bytes Sent since the broker started
  454. ### Packets sent and received
  455. Topic | Description
  456. -------------------------|------------
  457. packets/received | MQTT Packets received
  458. packets/sent | MQTT Packets sent
  459. packets/connect | MQTT CONNECT Packet received
  460. packets/connack | MQTT CONNACK Packet sent
  461. packets/publish/received | MQTT PUBLISH packets received
  462. packets/publish/sent | MQTT PUBLISH packets sent
  463. packets/subscribe | MQTT SUBSCRIBE Packets received
  464. packets/suback | MQTT SUBACK packets sent
  465. packets/unsubscribe | MQTT UNSUBSCRIBE Packets received
  466. packets/unsuback | MQTT UNSUBACK Packets sent
  467. packets/pingreq | MQTT PINGREQ packets received
  468. packets/pingresp | MQTT PINGRESP Packets sent
  469. packets/disconnect | MQTT DISCONNECT Packets received
  470. ### Messages sent and received
  471. Topic | Description
  472. ---------------------------------------|-------------------
  473. messages/received | Messages Received
  474. messages/sent | Messages Sent
  475. messages/retained | Messages Retained
  476. messages/stored | TODO: Messages Stored
  477. messages/dropped | Messages Dropped
  478. ## Alarm Topics
  479. Start with '$SYS/brokers/${node}/alarms/'
  480. Topic | Description
  481. -----------------|-------------------
  482. ${alarmId}/alert | New Alarm
  483. ${alarmId}/clear | Clear Alarm
  484. ## Log
  485. '$SYS/brokers/${node}/logs/${severity}'
  486. Severity | Description
  487. -----------|-------------------
  488. debug | Debug Log
  489. info | Info Log
  490. notice | Notice Log
  491. warning | Warning Log
  492. error | Error Log
  493. critical | Critical Log
  494. ## Sysmon
  495. Start with '$SYS/brokers/${node}/sysmon/'
  496. Topic | Description
  497. -----------------|-------------------
  498. long_gc | Long GC Warning
  499. long_schedule | Long Schedule
  500. large_heap | Large Heap Warning
  501. busy_port | Busy Port Warning
  502. busy_dist_port | Busy Dist Port
  503. ## Log
  504. '$SYS/brokers/${node}/log/${severity}'
  505. Severity | Description
  506. ------------|-------------------
  507. debug | Debug
  508. info | Info Log
  509. notice | Notice Log
  510. warning | Warning Log
  511. error | Error Log
  512. critical | Critical Log
  513. alert | Alert Log
  514. ## VM Load Topics
  515. Start with '$SYS/brokers/${node}/vm/'
  516. Topic | Description
  517. -----------------|-------------------
  518. memory/* | TODO
  519. cpu/* | TODO
  520. processes/* | TODO
  521. ## Sys Interval
  522. sys_interval: 1 minute default
  523. ---------------------
  524. Trace Topic or Client
  525. ---------------------
  526. .. _emqttd_plugin_mysql: https://github.com/emqtt/emqttd_plugin_mysql
  527. .. _emqttd_plugin_pgsql: https://github.com/emqtt/emqttd_plugin_pgsql
  528. .. _emqttd_plugin_redis: https://github.com/emqtt/emqttd_plugin_redis