JavaScript date validation
The logic you're using for validating a date looks fine to me.

The code is not bad, but here are a few suggestions for improvement:

IIFE

All of the defined variables and functions leak into global scope. Put them all inside the IIFE to avoid the scope leak: (Note the trailing semicolon)

(function(){
    var _monthList = ...
    function createYears() {
        ...
    }

    ...

    createYears();
    createMonths();
    createDates();
    registerEvents();
})();


And it's better to execute this function only when the document is ready, so it works regardless of when the script is loaded:

$(function() {
    ...
});


Naming


Don't prefix your variable names with an underscore. This convention is only used for private properties of objects, which you don't have in your code.
Use day instead of date when you mean the day of the month (e.g. createDays, days, #cbDay, day), Javascript's Date#getDate method is poorly named. Then you can rename dateObj to date.
Don't prefix your elements' IDs with cb (they're not callbacks). Simply use year, month and day (element IDs don't clash with variable/function names, so they don't need to be prefixed).
lblError -> errorLabel. No need to abbreviate.
dataset -> options, to be more descriptive.


Make each function do one thing

createYears both generates the year array and manipulates the DOM. Generate the array outside the function instead: (like you did for createMonths)

var yearList = (function() {
    var years = [];
    for (var i = 2000; i&lt;=new Date().getFullYear(); i++){
        years.push({id:i, name:i});
    }
    return years;
})();


Do the same for createDays.

validateDate both checks if the date is valid and updates #errorLabel accordingly. Use a seperate function for testing if a date is valid:

function isDateValid(day, month, year) {
    var date = new Date(year, month-1, day);
    return day == date.getDate();
}


createOptions

Every time createOptions is called, the return value is set as the HTML value of an element. It's better to pass the element to createOptions as an argument and let it manipulate the element to eliminate this repetition.

Each option passed to this function is known to have id and name properties, so you don't need to check which properties are present.

You don't need to set the IDs for the options, it's enough to set the values. This means the id property of the options in the array argument should be renamed to value (Change id to value when generating the arrays).

Finally, you can use jQuery for creating the elements:

function createOptions(select, options) {
    options.forEach(function (option) {
        select.append($('&lt;option&gt;', { text: option.name, value: option.value }));
    });
}


Now createYears looks like this:

function createYears() {
    createOptions($('#year'), yearList);
}


Which is so short that there is no need to make createYears, createMonths and createDays multiple functions.

Seperating logic from DOM

Put all the functions that are responsible for the logic first, and after them put code that accesses the page's DOM: (i.e. code that has strings with specific element IDs)

var dayList = ...;
var monthList = ...;
var yearList = ...;

function createOptions(select, options){
    ...
}

function isDateValid(day, month, year) {
    ...
}

createOptions($('#year'), yearList);
createOptions($('#month'), monthList);
createOptions($('#day'), dayList);

$("select").on("change", function validateDate() {
    var day = $("#day").val(); /* NOTE: No need to use additional selectors when you're already selecting by ID */
    var month = $("#month").val();
    var year = $("#year").val();
    if(year &amp;&amp; month &amp;&amp; day) {
        /* NOTE: I used a ternary expression to shorten the code */
        $("#errorLabel").text(isDateValid(day, month, year) ? "" : "Please select a valid date");
    }
});


This makes the code easier to understand and more reusable (e.g. it will make having multiple date forms on the same page easier).

Good luck!