You should remember that regex was designed for matching a date (or not). Saying that a date is valid is a much more complicated struggle, since it will require a lot of exception handling (see leap year conditions).
Let's start by matching the month (1 - 12) with an optional leading 0:
0?[1-9]|1[0-2]
To match the day, also with an optional leading 0:
0?[1-9]|[12][0-9]|3[01]
And to match the year (let's just assume the range 1900 - 2999):
(?:19|20)[0-9]{2}
The separator can be a space, a dash, a slash, empty, etc. Feel free to add anything you feel may be used as a separator:
[-\\/ ]?
Now you concatenate the whole thing and get:
(0?[1-9]|1[0-2])[-\\/ ]?(0?[1-9]|[12][0-9]|3[01])[-/ ]?(?:19|20)[0-9]{2} // MMDDYYYY
(0?[1-9]|[12][0-9]|3[01])[-\\/ ]?(0?[1-9]|1[0-2])[-/ ]?(?:19|20)[0-9]{2} // DDMMYYYY
(?:19|20)[0-9]{2}[-\\/ ]?(0?[1-9]|1[0-2])[-/ ]?(0?[1-9]|[12][0-9]|3[01]) // YYYYMMDD
If you want to be a bit more pedantic, you can use a back reference to be sure that the two separators will be the same:
(0?[1-9]|1[0-2])([-\\/ ]?)(0?[1-9]|[12][0-9]|3[01])\2(?:19|20)[0-9]{2} // MMDDYYYY
^ refer to [-/ ]
(0?[1-9]|[12][0-9]|3[01])([-\\/ ]?)(0?[1-9]|1[0-2])\2(?:19|20)[0-9]{2} // DDMMYYYY
(?:19|20)[0-9]{2}([-\\/ ]?)(0?[1-9]|1[0-2])\2(0?[1-9]|[12][0-9]|3[01]) // YYYYMMDD