When using platformio, add this in lib_deps:

knolleary/PubSubClient @ ^2.8

Create mqtt.h and include it in the main source code, define the MQTT_HOST, MQTT_PORT and MQTT_TOPIC as well:

const char *mqtt_broker = "broker.emqx.io";  // EMQX broker endpoint
const char *mqtt_topic = "emqx/esp8266";     // MQTT topic
const char *mqtt_username = "emqx";  // MQTT username for authentication
const char *mqtt_password = "public";  // MQTT password for authentication
const int mqtt_port = 1883;  // MQTT port (TCP)

const char *lwt_topic = "esp8266/status";
const char *lwt_message = "device is offline now";
const int lwt_qos = 1;
const bool lwt_retain = true;

#include "mqtt.h"

Code for mqtt.h (including Last Will and Testament (LWT):

#include <PubSubClient.h>

PubSubClient mqtt_client;

bool mqttconnected = false;
struct mqttdatastruct { 
    String message; 
    bool cleared; 
    unsigned long millis;
};

mqttdatastruct mqttdata;

void mqttCallback(char *topic, byte *payload, unsigned int length) {
    Serial.print("Message received on topic: ");
    Serial.println(topic);
    Serial.print("Message:");
    for (unsigned int i = 0; i < length; i++) {
        Serial.print((char) payload[i]);
    }
    Serial.println();
    Serial.println("-----------------------");
}

void connectomqttbroker(){
    while (!mqtt_client.connected()) {
        String client_id = "esp8266-client-" + String(WiFi.macAddress());
        Serial.printf("Connecting to MQTT Broker as %s.....\n", client_id.c_str());
        if (mqtt_client.connect(client_id.c_str(), mqtt_username, mqtt_password,lwt_topic,lwt_qos,lwt_retain,lwt_message)) {
            Serial.println("Connected to MQTT broker");
            mqtt_client.subscribe(mqtt_topic);
            // Publish message upon successful connection
            mqtt_client.publish(mqtt_topic, "Hi EMQX I'm ESP8266 ^^");
        } else {
            Serial.print("Failed to connect to MQTT broker, rc=");
            Serial.print(mqtt_client.state());
            Serial.println(" try again in 5 seconds");
            delay(5000);
        }
    }
}    

void initializemqtt() {
    mqtt_client.setServer(mqtt_broker, mqtt_port);
    mqtt_client.setCallback(mqttCallback);
    connectomqttbroker();
}

To Subscribe or Publish:

mqtt_client.subscribe(mqtt_topic);
mqtt_client.publish(mqtt_topic, "Hi EMQX I'm ESP8266 ^^");

To reconnect if disconnected:

void loop() {
    if (!mqtt_client.connected()) {
        connectomqttbroker();
    }
    mqtt_client.loop();
}

Below link:

https://docs.emqx.com/en/cloud/latest/connect_to_deployments/esp8266.html